<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="ja" lang="ja">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<link href="../css/main.css" media="all" rel="stylesheet" type="text/css" />
<link href="../css/highlight.css" media="all" rel="stylesheet" type="text/css" />
<link href="../css/print.css" media="print" rel="stylesheet" type="text/css" />
<title>第7章 - ビューレイヤーの内側</title>
</head>

<body>
<div class="navigation">

<table width="100%">
<tr>
<td width="40%" align="left"><a href="06-Inside-the-Controller-Layer.html">前の章</a></td>
<td width="20%" align="center"><a href="index.html">ホーム</a></td>
<td width="40%" align="right"><a href="08-Inside-the-Model-Layer.html">次の章</a></td>
</tr>
</table>
<hr/>
</div>

<div>
<a name="chapter.7.inside.the.view.layer" id="chapter.7.inside.the.view.layer"></a><h1>第7章 - ビューレイヤーの内側</h1>

<p>ビュー(view)は特定のアクションと関連づけされた出力をレンダリングする仕事を引き受けます。symfonyにおいて、ビューは複数の部分から構成され、それぞれの部分にとり組む人達が簡単に修正できるように設計されています。</p>

<ul>
<li>Webデザイナーは一般的にテンプレート(現在のアクションのデータのプレゼンテーション)と(すべてのページに共通なコードを含む)レイアウトにとり組みます。これらはHTMLで書かれ、大部分がヘルパーの呼び出しである、PHPの埋め込みコードの塊(チャンク)です。</li>
<li>再利用のために、開発者は通常テンプレートコードのフラグメント(fragment - 断片)を部分テンプレート(partial - パーシャル)もしくはコンポーネント(component)にまとめます。これらはレイアウトの複数の領域に影響を与えるスロット(slot)とコンポーネントスロット(component slot)を使います。Webデザイナーもこれらのテンプレートのフラグメントにとり組むことができます。</li>
<li>開発者は(レスポンスのプロパティとほかのインターフェイスの要素を設定する)ビューのYAML設定ファイルとレスポンスオブジェクトにとり組みます。テンプレートのなかで変数を扱うとき、クロスサイトスクリプティング(XSS - Cross-Site Scripting)のリスクを無視してはなりませんし、ユーザーのデータを安全に記録するために出力エスケーピングのテクニックをよく理解していることが求められます。</li>
</ul>

<p>しかしながら、あなたの役割が何であれ、アクションの結果を表現する退屈な作業を速くする便利なツールを見ることになります。この章ではこれらすべてのツールをカバーします。</p>

<div class="toc">
<dl>
<dt><a href="#templating">7.1. テンプレートを利用する</a></dt>
<dd><dl>
<dt><a href="#helpers">7.1.1. ヘルパー</a></dt>
<dd><dl>
<dt><a href="#declaring.helpers">7.1.1.1. ヘルパーを宣言する</a></dt>
<dt><a href="#frequently.used.helpers">7.1.1.2. よく使われるヘルパー</a></dt>
</dl></dd>
<dt><a href="#adding.your.own.helpers">7.1.2. 独自のヘルパーを追加する</a></dt>
<dt><a href="#page.layout">7.1.3. ページのレイアウト</a></dt>
<dt><a href="#template.shortcuts">7.1.4. テンプレートのショートカット</a></dt>
</dl></dd>
<dt><a href="#code.fragments">7.2. コードのフラグメント</a></dt>
<dd><dl>
<dt><a href="#partials">7.2.1. 部分テンプレート</a></dt>
<dt><a href="#components">7.2.2. コンポーネント</a></dt>
<dt><a href="#slots">7.2.3. スロット</a></dt>
</dl></dd>
<dt><a href="#view.configuration">7.3. ビューのコンフィギュレーション</a></dt>
<dd><dl>
<dt><a href="#the.view.yml.file">7.3.1. view.ymlファイル</a></dt>
<dt><a href="#the.response.object">7.3.2. レスポンスオブジェクト</a></dt>
<dt><a href="#view.configuration.settings">7.3.3. ビューのコンフィギュレーション設定</a></dt>
<dt><a href="#meta.tag.configuration">7.3.4. メタタグのコンフィギュレーション</a></dt>
<dt><a href="#title.configuration">7.3.5. タイトルのコンフィギュレーション</a></dt>
<dt><a href="#file.inclusion.configuration">7.3.6. ファイルのインクルードコンフィギュレーション</a></dt>
<dt><a href="#layout.configuration">7.3.7. レイアウトのコンフィギュレーション</a></dt>
</dl></dd>
<dt><a href="#component.slots">7.4. コンポーネントスロット</a></dt>
<dt><a href="#output.escaping">7.5. 出力エスケーピング機能</a></dt>
<dd><dl>
<dt><a href="#activating.output.escaping">7.5.1. 出力エスケーピング機能を有効にする</a></dt>
<dt><a href="#escaping.helpers">7.5.2. エスケーピングヘルパー</a></dt>
<dt><a href="#escaping.arrays.and.objects">7.5.3. 配列とオブジェクトをエスケープする</a></dt>
</dl></dd>
<dt><a href="#summary">7.6. まとめ</a></dt>
</dl>
</div>
<a name="templating" id="templating"></a><h2>テンプレートを利用する</h2>

<p>リスト7-1はsymfonyの典型的なテンプレートを示しています。HTMLコードと基本的なPHPコード、通常はアクション(<code>$this-&gt;name = 'foo';</code>)とヘルパーで定義された変数の呼び出しが含まれます。</p>

<p>リスト7-1 - テンプレートのサンプル(indexSuccess.php)</p>

<pre class="php">&lt;h1&gt;ようこそ&lt;/h1&gt;
&lt;p&gt;お帰りなさい、<span class="kw2">&lt;?php</span> <span class="kw1">echo</span> <span class="re0">$name</span> <span class="sy1">?&gt;</span>！&lt;/p&gt;
&lt;ul&gt;何をなさりたいですか？
  &lt;li&gt;<span class="kw2">&lt;?php</span> <span class="kw1">echo</span> link_to<span class="br0">&#40;</span><span class="st_h">'最新の記事を読む'</span><span class="sy0">,</span> <span class="st_h">'article/read'</span><span class="br0">&#41;</span> <span class="sy1">?&gt;</span>&lt;/li&gt;
  &lt;li&gt;<span class="kw2">&lt;?php</span> <span class="kw1">echo</span> link_to<span class="br0">&#40;</span><span class="st_h">'新しい記事を書き始める'</span><span class="sy0">,</span> <span class="st_h">'article/write'</span><span class="br0">&#41;</span> <span class="sy1">?&gt;</span>&lt;/li&gt;
&lt;/ul&gt;</pre>

<p>4章で説明したように、テンプレートのなかではPHP開発者ではない人が読みやすいようにPHPの代替構文が望ましいです。テンプレートのなかではPHPコードは最小限に保つべきです。これらのファイルはアプリケーションのGUIを設計するために使われ、時々、別のチームによって作成とメンテナンスが行われ、アプリケーションのロジックではなくプレゼンテーションに特化されているからです。ロジックをアクション内部に保つことで、コードを重複させずに、1つのアクションを共有する複数のテンプレートを持つことが簡単になります。</p>

<a name="helpers" id="helpers"></a><h3>ヘルパー</h3>

<p>ヘルパーはPHP関数でHTMLコードを返し、テンプレートのなかで使うことができます。リスト7-1において<code>link_to()</code>関数はヘルパーです。時々、テンプレート内でよく使われるコードスニペット(断片)をまとめることで、ヘルパーは時間を節約します。たとえば、つぎのヘルパーの関数定義は簡単に想像がつきます。</p>

<pre class="php"><span class="kw2">&lt;?php</span> <span class="kw1">echo</span> input_tag<span class="br0">&#40;</span><span class="st_h">'nickname'</span><span class="br0">&#41;</span> <span class="sy1">?&gt;</span>
 =&gt; &lt;input type=&quot;text&quot; name=&quot;nickname&quot; id=&quot;nickname&quot; value=&quot;&quot; /&gt;</pre>

<p>上記のコードはリスト7-2のようになります。</p>

<p>リスト7-2 - ヘルパー定義のサンプル</p>

<pre class="php"><span class="kw2">function</span> input_tag<span class="br0">&#40;</span><span class="re0">$name</span><span class="sy0">,</span> <span class="re0">$value</span> <span class="sy0">=</span> <span class="kw4">null</span><span class="br0">&#41;</span>
<span class="br0">&#123;</span>
  <span class="kw1">return</span> <span class="st_h">'&lt;input type=&quot;text&quot; name=&quot;'</span><span class="sy0">.</span><span class="re0">$name</span><span class="sy0">.</span><span class="st_h">'&quot; id=&quot;'</span><span class="sy0">.</span><span class="re0">$name</span><span class="sy0">.</span><span class="st_h">'&quot;value=&quot;'</span><span class="sy0">.</span><span class="re0">$value</span><span class="sy0">.</span><span class="st_h">'&quot; /&gt;'</span><span class="sy0">;</span>
<span class="br0">&#125;</span></pre>

<p>実際のところ、symfonyに組み込まれている<code>input_tag()</code>関数は、ほかの属性を<code>&lt;input&gt;</code>タグに追加する3番目のパラメーターを受けとるので、上記のコードよりも少々複雑です。完全な構文とオプションはAPIドキュメント(<a href="http://www.symfony-project.org/api/1_2/">http://www.symfony-project.org/api/1_2/</a>)で確認できます。</p>

<p>たいていの場合、ヘルパーは賢いので長くて複雑なコードを書かずにすみます。</p>

<pre class="php"><span class="kw2">&lt;?php</span> <span class="kw1">echo</span> auto_link_text<span class="br0">&#40;</span><span class="st_h">'我々のサイトにお越しください www.example.com'</span><span class="br0">&#41;</span> <span class="sy1">?&gt;</span>
 =&gt; 我々のサイトにお越しください &lt;a href=&quot;http://www.example.com&quot;&gt;www.example.com&lt;/a&gt;</pre>

<p>ヘルパーはテンプレートを書く作業工程を円滑にし、パフォーマンスとアクセシビリティの観点から最高のHTMLコードを生み出します。つねに無地のHTMLを使うことができますが、ヘルパーのほうがより速く書けます。</p>

<blockquote class="tip"><p>
  なぜヘルパーがsymfony内部のすべての場所で使われているcamelCase(キャメルケース)の規約ではなくアンダースコアの構文にしたがって命名されるのか疑問に思っていらっしゃるかもしれません。これはヘルパーが関数であり、PHPのコア関数すべてがアンダースコアの構文の規約を利用するからです。</p>
</blockquote>

<a name="declaring.helpers" id="declaring.helpers"></a><h4>ヘルパーを宣言する</h4>

<p>ヘルパーの定義を含むsymfonyのファイルはオートロードされません(これらがクラスではなく関数を含むからです)。ヘルパーは目的によって分類されます。たとえば、テキストを扱うすべてのヘルパー関数は<code>TextHelper.php</code>という名前のファイルで定義され、<code>Text</code>ヘルパーグループと呼ばれます。ですのでヘルパーをテンプレートのなかで使う必要がある場合、<code>use_helper()</code>関数でヘルパーを宣言することで最初の段階で関連のヘルパーグループをロードしなければなりません。リスト7-3は、<code>Text</code>ヘルパーグループの一部である、<code>auto_link_text()</code>ヘルパーを使うテンプレートを示しています。</p>

<p>リスト7-3 ヘルパーの使用を宣言する</p>

<pre class="php">// このテンプレートのなかで特定のヘルパーグループを使う
<span class="kw2">&lt;?php</span> use_helper<span class="br0">&#40;</span><span class="st_h">'Text'</span><span class="br0">&#41;</span> <span class="sy1">?&gt;</span>
...
&lt;h1&gt;説明&lt;/h1&gt;
&lt;p&gt;<span class="kw2">&lt;?php</span> <span class="kw1">echo</span> auto_link_text<span class="br0">&#40;</span><span class="re0">$description</span><span class="br0">&#41;</span> <span class="sy1">?&gt;</span>&lt;/p&gt;</pre>

<blockquote class="tip"><p>
  複数のヘルパーグループを宣言する必要がある場合、より多くの引数を<code>use_helper()</code>呼び出しに追加します。たとえば、<code>Text</code>と<code>Javascript</code>ヘルパーグループの両方をテンプレートにロードするには、<code>&lt;?php use_helper('Text', 'Javascript') ?&gt;</code>を呼び出します。</p>
</blockquote>

<p>いくつかのヘルパーは、すべてのテンプレートのなかで宣言を行わずにデフォルトで利用できます。ヘルパーグループのヘルパーはつぎのようなものがあります:</p>

<ul>
<li><code>Helper</code>: ヘルパーのインクルードに必要(<code>use_helper()</code>関数は、実際、ヘルパーそのもの)</li>
<li><code>Tag</code>: ほとんどすべてのヘルパーによって使われる、基本的なタグヘルパー </li>
<li><code>Url</code>: リンクとURLを管理するヘルパー</li>
<li><code>Asset</code>: HTMLの<code>&lt;head&gt;</code>セクションの投入と外部アセット(画像、JavaScriptとCSS)への簡単なリンクを提供するヘルパー</li>
<li><code>Partial</code>: テンプレートフラグメントをインクルードできるようにするヘルパー</li>
<li><code>Cache</code>: キャッシュされたコードフラグメントを操作するヘルパー</li>
<li><code>Form</code>: フォーム入力のヘルパー</li>
</ul>

<p>すべてのテンプレート用にデフォルトでロードされる、標準ヘルパーのリストは<code>settings.yml</code>ファイルのなかで設定できます。<code>Cache</code>グループのヘルパーを使わない、もしくは<code>Text</code>グループのヘルパーをつねに使うことがわかっている場合、<code>standard_helpers</code>設定をそれぞれ変更します。これによってアプリケーションの動作を少し加速します。前のリストにある最初の4つのヘルパーグループ(<code>Helper</code>、<code>Tag</code>、<code>Url</code>、<code>Asset</code>)は削除できません。なぜなら、テンプレートエンジンが適切に動作するために必須だからです。結果として、標準ヘルパーのリストにも表示されません。</p>

<blockquote class="tip"><p>
  テンプレート外部でヘルパーを使う必要がある場合、<code>sfProjectConfiguration::getActive()-&gt;loadHelpers($helpers)</code>を呼び出すことでどこからでもヘルパーグループをロードできます。<code>$helpers</code>はヘルパーグループの名前もしくはヘルパーグループ名の配列です。たとえば、アクションのなかで<code>auto_link_text()</code>を使いたい場合、<code>sfProjectConfiguration::getActive()-&gt;loadHelpers('Text')</code>を最初に呼び出す必要があります。</p>
</blockquote>

<a name="frequently.used.helpers" id="frequently.used.helpers"></a><h4>よく使われるヘルパー</h4>

<p>ヘルパーが助けしてくれる機能に関連する、いくつかのヘルパーに関する詳細な内容は後の章で学ぶことになります。リスト7-4では、ヘルパーが返すHTMLコードと一緒に、よく使われるデフォルトのヘルパーの手短な一覧を示しています。</p>

<p>リスト7-4 - デフォルトの共通ヘルパー</p>

<pre class="php">// Helperグループ
<span class="kw2">&lt;?php</span> use_helper<span class="br0">&#40;</span><span class="st_h">'HelperName'</span><span class="br0">&#41;</span> <span class="sy1">?&gt;</span>
<span class="kw2">&lt;?php</span> use_helper<span class="br0">&#40;</span><span class="st_h">'HelperName1'</span><span class="sy0">,</span> <span class="st_h">'HelperName2'</span><span class="sy0">,</span> <span class="st_h">'HelperName3'</span><span class="br0">&#41;</span> <span class="sy1">?&gt;</span>
&nbsp;
// Tagグループ
<span class="kw2">&lt;?php</span> <span class="kw1">echo</span> tag<span class="br0">&#40;</span><span class="st_h">'input'</span><span class="sy0">,</span> <span class="kw3">array</span><span class="br0">&#40;</span><span class="st_h">'name'</span> <span class="sy0">=&gt;</span> <span class="st_h">'foo'</span><span class="sy0">,</span> <span class="st_h">'type'</span> <span class="sy0">=&gt;</span> <span class="st_h">'text'</span><span class="br0">&#41;</span><span class="br0">&#41;</span> <span class="sy1">?&gt;</span>
<span class="kw2">&lt;?php</span> <span class="kw1">echo</span> tag<span class="br0">&#40;</span><span class="st_h">'input'</span><span class="sy0">,</span> <span class="st_h">'name=foo type=text'</span><span class="br0">&#41;</span> <span class="sy1">?&gt;</span>  // 代替のオプション構文
 =&gt; &lt;input name=&quot;foo&quot; type=&quot;text&quot; /&gt;
<span class="kw2">&lt;?php</span> <span class="kw1">echo</span> content_tag<span class="br0">&#40;</span><span class="st_h">'textarea'</span><span class="sy0">,</span> <span class="st_h">'ダミーの内容'</span><span class="sy0">,</span> <span class="st_h">'name=foo'</span><span class="br0">&#41;</span> <span class="sy1">?&gt;</span>
 =&gt; &lt;textarea name=&quot;foo&quot;&gt;ダミーの内容&lt;/textarea&gt;
&nbsp;
// Urlグループ
<span class="kw2">&lt;?php</span> <span class="kw1">echo</span> link_to<span class="br0">&#40;</span><span class="st_h">'クリックしてください'</span><span class="sy0">,</span> <span class="st_h">'mymodule/myaction'</span><span class="br0">&#41;</span> <span class="sy1">?&gt;</span>
=&gt; &lt;a href=&quot;/route/to/myaction&quot;&gt;クリックしてください&lt;/a&gt;  // ルーティングの設定による
&nbsp;
// Assetグループ
<span class="kw2">&lt;?php</span> <span class="kw1">echo</span> image_tag<span class="br0">&#40;</span><span class="st_h">'myimage'</span><span class="sy0">,</span> <span class="st_h">'alt=foo size=200x100'</span><span class="br0">&#41;</span> <span class="sy1">?&gt;</span>
 =&gt; &lt;img src=&quot;/images/myimage.png&quot; alt=&quot;foo&quot; width=&quot;200&quot; height=&quot;100&quot;/&gt;
<span class="kw2">&lt;?php</span> <span class="kw1">echo</span> javascript_include_tag<span class="br0">&#40;</span><span class="st_h">'myscript'</span><span class="br0">&#41;</span> <span class="sy1">?&gt;</span>
 =&gt; &lt;script language=&quot;JavaScript&quot; type=&quot;text/javascript&quot; src=&quot;/js/myscript.js&quot;&gt;&lt;/script&gt;
<span class="kw2">&lt;?php</span> <span class="kw1">echo</span> stylesheet_tag<span class="br0">&#40;</span><span class="st_h">'style'</span><span class="br0">&#41;</span> <span class="sy1">?&gt;</span>
 =&gt; &lt;link href=&quot;/stylesheets/style.css&quot; media=&quot;screen&quot; rel=&quot;stylesheet&quot;type=&quot;text/css&quot; /&gt;</pre>

<p>symfonyにはほかの多くのヘルパーが存在し、それらすべてを説明するには一冊の本が必要になります。ヘルパーの最良のリファレンスはオンラインのAPIドキュメント(<a href="http://www.symfony-project.org/api/1_2/">http://www.symfony-project.org/api/1_2/</a>)です。そこですべてのヘルパーの構文、オプションと例について十分な説明があります。</p>

<a name="adding.your.own.helpers" id="adding.your.own.helpers"></a><h3>独自のヘルパーを追加する</h3>

<p>symfonyはさまざまな目的のために多くのヘルパーを搭載していますが、APIドキュメントで必要なものが見つからない場合、新しいヘルパーを作りたいと思うでしょう。これはとても簡単に行うことができます。</p>

<p>ヘルパー関数(HTMLコードを返す通常のPHP関数)は<code>FooBarHelper.php</code>という名前のファイルに保存されます。<code>FooBar</code>はヘルパーグループの名前です。<code>use_helper('FooBar')</code>ヘルパーによってファイルが自動的に発見されインクルードされるために、ファイルは<code>apps/frontend/lib/helper/</code>に保存されます(もしくはプロジェクトの<code>lib/</code>フォルダーの1つのもとで作られた<code>helper/</code>ディレクトリ)。</p>

<blockquote class="tip"><p>
  このシステムによって既存のsymfonyヘルパーをオーバーライドすることもできます。たとえば、<code>Text</code>ヘルパーグループのすべてのヘルパーを再定義するために、 <code>TextHelper.php</code>ファイルを<code>apps/frontend/lib/helper/</code>ディレクトリに作ります。<code>use_helper('Text')</code>を呼び出すたびに、symfonyは固有のヘルパーよりあなたのヘルパーグループを使います。しかしつぎのことに気をつけてください: オリジナルのファイルがロードされない場合、そのファイルをオーバーライドするすべてのヘルパーグループの関数を再定義しなければなりません; さもなければ、いくつかのオリジナルのヘルパーはまったく利用できなくなります。</p>
</blockquote>

<a name="page.layout" id="page.layout"></a><h3>ページのレイアウト</h3>

<p>リスト7-1で示されているテンプレートには<code>DOCTYPE</code>の定義と<code>&lt;html&gt;</code>と<code>&lt;body&gt;</code>タグが見つからないので、有効なXHTMLドキュメントではありません。これらが、アプリケーションのほかの場所に存在し、ページのレイアウトを含む<code>layout.php</code>ファイルに保存されるからです。このファイルは、グローバルレイアウト(global template)とも呼ばれますが、すべてのテンプレートのなかで繰り返しを避けるためにアプリケーションのすべてのページに共通なHTMLコードを保存します。テンプレートの内容をレイアウトに統合されます。または見方を変えるなら、レイアウトはテンプレートを"デコレート"(装飾)します。図7-1で説明されるように、これはDecoratorデザインパターンのアプリケーションです。</p>

<blockquote class="tip"><p>
  Decoratorとほかのデザインパターンについて詳しい情報はMartin Fowler(マーチン・ファウラー)が執筆したPatterns of Enterprise Application Architecture(Addison-Wesley、ISBN: 0-32112-742-0)をご覧ください(邦訳は「エンタープライズアプリケーションアーキテクチャパターン」翔泳社、2005年 ISBN 4798105538)。</p>
</blockquote>

<p>図7-1 - レイアウトのなかでテンプレートをデコレートする</p>

<p><img src="images/F0701.png" alt="レイアウトのなかでテンプレートをデコレートする" title="レイアウトのなかでテンプレートをデコレートする" /></p>

<p>リスト7-5は、アプリケーションの<code>templates/</code>ディレクトリのなかに設置された、デフォルトのページレイアウトを示しています。</p>

<p>リスト7-5 - デフォルトのレイアウト(<code>myproject/apps/frontend/templates/layout.php</code>)</p>

<pre class="php">&lt;!DOCTYPE html PUBLIC &quot;-//W3C//DTD XHTML 1.0 Transitional//EN&quot; &quot;http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd&quot;&gt;
&lt;html xmlns=&quot;http://www.w3.org/1999/xhtml&quot; xml:lang=&quot;en&quot; lang=&quot;en&quot;&gt;
  &lt;head&gt;
    <span class="kw2">&lt;?php</span> include_http_metas<span class="br0">&#40;</span><span class="br0">&#41;</span> <span class="sy1">?&gt;</span>
    <span class="kw2">&lt;?php</span> include_metas<span class="br0">&#40;</span><span class="br0">&#41;</span> <span class="sy1">?&gt;</span>
    <span class="kw2">&lt;?php</span> include_title<span class="br0">&#40;</span><span class="br0">&#41;</span> <span class="sy1">?&gt;</span>
    &lt;link rel=&quot;shortcut icon&quot; href=&quot;/favicon.ico&quot; /&gt;
  &lt;/head&gt;
  &lt;body&gt;
    <span class="kw2">&lt;?php</span> <span class="kw1">echo</span> <span class="re0">$sf_content</span> <span class="sy1">?&gt;</span>
  &lt;/body&gt;
&lt;/html&gt;</pre>

<p><code>&lt;head&gt;</code>セクションに呼び出されたヘルパーはレスポンスオブジェクトとビューの設定から情報を取得します。<code>&lt;body&gt;</code>タグはテンプレートの結果を出力します。このレイアウトでは、デフォルトの設定とリスト7-1のサンプルのテンプレートおよび処理されたビューはリスト7-6のようになります。</p>

<p>リスト7-6 - 組み立てられたレイアウト、ビューの設定、とテンプレート</p>

<pre class="php">&lt;!DOCTYPE html PUBLIC &quot;-//W3C//DTD XHTML 1.0 Transitional//EN&quot; &quot;http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd&quot;&gt;
&lt;html xmlns=&quot;http://www.w3.org/1999/xhtml&quot; xml:lang=&quot;en&quot; lang=&quot;en&quot;&gt;
  &lt;head&gt;
    &lt;meta http-equiv=&quot;content-type&quot; content=&quot;text/html; charset=utf-8&quot; /&gt;
    &lt;meta name=&quot;title&quot; content=&quot;symfony project&quot; /&gt;
    &lt;meta name=&quot;robots&quot; content=&quot;index, follow&quot; /&gt;
    &lt;meta name=&quot;description&quot; content=&quot;symfony project&quot; /&gt;
    &lt;meta name=&quot;keywords&quot; content=&quot;symfony, project&quot; /&gt;
    &lt;title&gt;symfonyのプロジェクト&lt;/title&gt;
    &lt;link rel=&quot;stylesheet&quot; type=&quot;text/css&quot; href=&quot;/css/main.css&quot; /&gt;
    &lt;link rel=&quot;shortcut icon&quot; href=&quot;/favicon.ico&quot;&gt;
  &lt;/head&gt;
  &lt;body&gt;
    &lt;h1&gt;ようこそ&lt;/h1&gt;
    &lt;p&gt;おかえり、<span class="kw2">&lt;?php</span> <span class="kw1">echo</span> <span class="re0">$name</span> <span class="sy1">?&gt;</span>!&lt;/p&gt;
    &lt;ul&gt;何をなさいますか？
      &lt;li&gt;<span class="kw2">&lt;?php</span> <span class="kw1">echo</span> link_to<span class="br0">&#40;</span><span class="st_h">'最近の記事を読む'</span><span class="sy0">,</span> <span class="st_h">'article/read'</span><span class="br0">&#41;</span> <span class="sy1">?&gt;</span>&lt;/li&gt;
      &lt;li&gt;<span class="kw2">&lt;?php</span> <span class="kw1">echo</span> link_to<span class="br0">&#40;</span><span class="st_h">'新しい記事を書き始める'</span><span class="sy0">,</span> <span class="st_h">'article/write'</span><span class="br0">&#41;</span> <span class="sy1">?&gt;</span>&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/body&gt;
&lt;/html&gt;</pre>

<p>それぞれのアプリケーションごとにグローバルテンプレートを完全にカスタマイズできます。必要なHTMLコードを追加します。このレイアウトはサイトのナビゲーション、ロゴなどを格納するためによく使われます。複数のレイアウトを用意することも可能で、それぞれのアクションで使われるレイアウトを選ぶことができます。今のところはJavaScriptとスタイルシートのインクルードは気にしないでください; この章の"ビューのコンフィギュレーション"のセクションで扱う方法を説明します。</p>

<a name="template.shortcuts" id="template.shortcuts"></a><h3>テンプレートのショートカット</h3>

<p>テンプレートにおいて、いくつかのsymfonyの変数はつねに利用可能です。symfonyのコアオブジェクトを通して、これらのショートカットはテンプレートのなかでもっとも共通に必要とされる情報にアクセスできます:</p>

<ul>
<li><code>$sf_context</code>: コンテキスト全体のオブジェクト(<code>sfContext</code>のインスタンス)</li>
<li><code>$sf_request</code>: リクエストオブジェクト(<code>sfRequest</code>のインスタンス)</li>
<li><code>$sf_params</code> : リクエストオブジェクトのパラメーター</li>
<li><code>$sf_user</code>   : 現在のユーザーセッションのオブジェクト(<code>sfUser</code>のインスタンス)</li>
</ul>

<p>以前の章で<code>sfRequest</code>と<code>sfUser</code>オブジェクトの便利なメソッドを詳細に説明しました。<code>$sf_request</code>と<code>$sf_user</code>変数を通してテンプレートのこれらのメソッドを実際に呼び出すことができます。たとえば、リクエストが<code>total</code>パラメーターを含む場合、その変数はつぎのようにテンプレートのなかで利用できます:</p>

<pre class="php">// 長いバージョン
<span class="kw2">&lt;?php</span> <span class="kw1">echo</span> <span class="re0">$sf_request</span><span class="sy0">-&gt;</span><span class="me1">getParameter</span><span class="br0">&#40;</span><span class="st_h">'total'</span><span class="br0">&#41;</span> <span class="sy1">?&gt;</span>
&nbsp;
// 短いバージョン
<span class="kw2">&lt;?php</span> <span class="kw1">echo</span> <span class="re0">$sf_params</span><span class="sy0">-&gt;</span><span class="me1">get</span><span class="br0">&#40;</span><span class="st_h">'total'</span><span class="br0">&#41;</span> <span class="sy1">?&gt;</span>
&nbsp;
// つぎのアクションコードと同等
echo $request-&gt;getParameter('total')</pre>

<a name="code.fragments" id="code.fragments"></a><h2>コードのフラグメント</h2>

<p>いくつかのページで同じHTMLもしくはPHPコードが必要になることがよくあります。コードの繰り返しを避けるには、多くの場合、PHPの<code>include()</code>ステートメントで十分です。</p>

<p>たとえば、アプリケーションの多くのテンプレートが同じコードフラグメントを必要とする場合、グローバルテンプレートのディレクトリ(<code>myproject/apps/frontend/templates/</code>)に存在する<code>myFragment.php</code>ファイルにフラグメントを保存し、つぎのようにそのファイルをテンプレートでインクルードします:</p>

<pre class="php"><span class="kw2">&lt;?php</span> <span class="kw1">include</span><span class="br0">&#40;</span>sfConfig<span class="sy0">::</span><span class="me2">get</span><span class="br0">&#40;</span><span class="st_h">'sf_app_template_dir'</span><span class="br0">&#41;</span><span class="sy0">.</span><span class="st_h">'/myFragment.php'</span><span class="br0">&#41;</span> <span class="sy1">?&gt;</span></pre>

<p>しかしこれはフラグメントをまとめるにはあまりきれいな方法ではありません。たいていの場合、フラグメントとそれを含むさまざまなテンプレートのあいだで異なる変数名を持つ可能性があるからです。加えて、symfonyのキャッシュシステム(12章で説明)はインクルードを検出する方法を持たないので、コードのフラグメントはテンプレートから独立してキャッシュされません。symfonyは<code>include</code>を置き換えるために、代わりとなる3つのタイプの賢いコードのフラグメントを提供します;</p>

<ul>
<li>ロジックが軽量の場合、テンプレートに渡すデータにアクセスするテンプレートファイルをインクルードするだけです。そのためには、部分テンプレート(partial)を使います。</li>
<li>ロジックが重い場合(たとえば、データモデルにアクセスして/もしくはセッションにしたがって内容を修正する場合)、プレゼンテーションをロジックから分離することが望ましいです。そのためには、コンポーネント(component)を使います。</li>
<li>コードのフラグメントでレイアウトの特定の部分を置き換えることを目的とする場合、すでに存在しているであろうデフォルトの内容に対して、スロット(slot)を使います。</li>
</ul>

<blockquote class="note"><p>
  コンポーネントスロット(component slot)と呼ばれる、別のコードのフラグメントのタイプはフラグメントの性質が文脈に依存するときに使われます(たとえば、コードのフラグメントが任意のモジュールのアクションに対して異なることが必要な場合)。コンポーネントスロットはこの章の後のほうで説明します。</p>
</blockquote>

<p>これらのコードのフラグメントのインクルードは<code>Partial</code>グループのヘルパーによって実現されます。これらのヘルパーは、初期化の宣言を行わずに、symfonyのどのテンプレートからも利用できます。</p>

<a name="partials" id="partials"></a><h3>部分テンプレート</h3>

<p>部分テンプレート(partial)は再利用可能なテンプレートコードの塊(チャンク)です。たとえば、情報公開を行うアプリケーションにおいて、記事を表示するテンプレートのコードは記事の詳細な内容のページに使われ、もっとも人気のある記事と最新の記事の一覧にも使われます。図7-2で示されるように、このコードは部分テンプレートのための完璧な候補です。</p>

<p>図7-2 - テンプレート内で部分テンプレートを再利用する</p>

<p><img src="images/F0702.png" alt="テンプレート内で部分テンプレートを再利用する" title="テンプレート内で部分テンプレートを再利用する" /></p>

<p>テンプレートのように、部分テンプレートは<code>templates/</code>ディレクトリに設置されたファイルで、これらはPHPが埋め込まれたHTMLコードを含みます。部分テンプレートのファイルの名前はつねにアンダースコア(<code>_</code>)で始まります。テンプレートが同じ<code>templates</code>フォルダーに設置されているので、これは部分テンプレートとテンプレートを区別するのに役立ちます。</p>

<p>部分テンプレートが同じモジュール、別のモジュール、もしくはグローバルな<code>templates/</code>ディレクトリにあったとしても、テンプレートは部分テンプレートをインクルードできます。リスト7-7に書かれているように、<code>include_partial()</code>ヘルパーを利用して部分テンプレートをインクルードして、モジュールと部分テンプレート名をパラメーターとして指定します(ただし先頭のアンダースコアと末尾の<code>.php</code>を省略します)。</p>

<p>リスト7-7 - 部分テンプレートを<code>mymodule</code>モジュールのテンプレートのなかに含める</p>

<pre class="php">// frontend/modules/mymodule/templates/_mypartial1.php部分テンプレートをインクルードする
// テンプレートと部分テンプレートは同じモジュールにあるので、
// モジュール名を省略できる
<span class="kw2">&lt;?php</span> include_partial<span class="br0">&#40;</span><span class="st_h">'mypartial1'</span><span class="br0">&#41;</span> <span class="sy1">?&gt;</span>
&nbsp;
// frontend/modules/foobar/templates/_mypartial2.php部分テンプレートをインクルードする
// この場合モジュール名は必須
<span class="kw2">&lt;?php</span> include_partial<span class="br0">&#40;</span><span class="st_h">'foobar/mypartial2'</span><span class="br0">&#41;</span> <span class="sy1">?&gt;</span>
&nbsp;
// frontend/templates/_mypartial3.php部分テンプレートをインクルードする
// 'global'モジュールの一部として見なされる
<span class="kw2">&lt;?php</span> include_partial<span class="br0">&#40;</span><span class="st_h">'global/mypartial3'</span><span class="br0">&#41;</span> <span class="sy1">?&gt;</span></pre>

<p>部分テンプレートはsymfonyの通常のヘルパーとテンプレートのショートカットにアクセスできます。しかし、部分テンプレートはアプリケーションのどこからでも呼び出すことができるので、部分テンプレートをインクルードするテンプレートを呼び出すアクションで定義された変数が明示的に引数として渡されないかぎり、部分テンプレートは変数に自動的にアクセスできません。たとえば、<code>$total</code>変数にアクセスできる部分テンプレートが欲しい場合、リスト7-8、7-9、7-10で示されるように、アクションは変数をテンプレートに渡さなければなりませんし、また、テンプレートは変数を<code>include_partial()</code>呼び出しの2番目の引数としてヘルパーに渡さなければなりません。</p>

<p>リスト7-8 - アクションは変数を定義する(<code>mymodule/actions/actions.class.php</code>)</p>

<pre class="php"><span class="kw2">class</span> mymoduleActions <span class="kw2">extends</span> sfActions
<span class="br0">&#123;</span>
  <span class="kw2">public</span> <span class="kw2">function</span> executeIndex<span class="br0">&#40;</span><span class="br0">&#41;</span>
  <span class="br0">&#123;</span>
    <span class="re0">$this</span><span class="sy0">-&gt;</span><span class="me1">total</span> <span class="sy0">=</span> <span class="nu0">100</span><span class="sy0">;</span>
  <span class="br0">&#125;</span>
<span class="br0">&#125;</span></pre>

<p>リスト7-9 - テンプレートが部分テンプレートに変数を渡す(<code>mymodule/templates/indexSuccess.php</code>)</p>

<pre class="php">&lt;p&gt;Hello, world!&lt;/p&gt;
<span class="kw2">&lt;?php</span> include_partial<span class="br0">&#40;</span><span class="st_h">'mypartial'</span><span class="sy0">,</span> <span class="kw3">array</span><span class="br0">&#40;</span><span class="st_h">'mytotal'</span> <span class="sy0">=&gt;</span> <span class="re0">$total</span><span class="br0">&#41;</span><span class="br0">&#41;</span> <span class="sy1">?&gt;</span></pre>

<p>リスト7-10 - 部分テンプレートは変数を使える(<code>mymodule/templates/_mypartial.php</code>)</p>

<pre class="php">&lt;p&gt;合計: <span class="kw2">&lt;?php</span> <span class="kw1">echo</span> <span class="re0">$mytotal</span> <span class="sy1">?&gt;</span>&lt;/p&gt;</pre>

<blockquote class="tip"><p>
  すべてのヘルパーはこれまで<code>&lt;?php echo functionName() ?&gt;</code>によって呼び出されてきました。通常のPHPの<code>include()</code>ステートメントと似たようなふるまいをするように、部分テンプレートのヘルパーは、<code>echo</code>することなく、<code>&lt;?php include_partial() ?&gt;</code>によって簡単に呼び出されます。実際に表示しないで部分テンプレートの内容を返す関数が必要な場合、代わりに<code>get_partial()</code>を使います。この章で説明されたすべての<code>include_</code>ヘルパーは<code>echo</code>ステートメントで一緒に呼び出すことができる<code>get_</code>で始まる対のヘルパーを持ちます。</p>
  
  <p><strong>TIP</strong>
  <strong>symfony 1.1の新しい機能</strong>: テンプレートで終わる代わりに、アクションは部分テンプレートもしくはコンポーネントを返します。アクションクラスの<code>renderPartial()</code>と<code>renderComponent()</code>メソッドはコードの再利用性を促進します。加えて、それらは部分テンプレートのキャッシュ機能を利用します(12章を参照)。アクションのなかで定義された変数は、変数の連想配列をメソッドの2番目の引数として定義しないかぎり、自動的に部分テンプレート/コンポーネントに渡されます。</p>

<pre class="php"><span class="kw2">public</span> <span class="kw2">function</span> executeFoo<span class="br0">&#40;</span><span class="br0">&#41;</span>
<span class="br0">&#123;</span>
  <span class="co1">// 何かを行う</span>
  <span class="re0">$this</span><span class="sy0">-&gt;</span><span class="me1">foo</span> <span class="sy0">=</span> <span class="nu0">1234</span><span class="sy0">;</span>
  <span class="re0">$this</span><span class="sy0">-&gt;</span><span class="me1">bar</span> <span class="sy0">=</span> <span class="nu0">4567</span><span class="sy0">;</span>
&nbsp;
  <span class="kw1">return</span> <span class="re0">$this</span><span class="sy0">-&gt;</span><span class="me1">renderPartial</span><span class="br0">&#40;</span><span class="st_h">'mymodule/mypartial'</span><span class="br0">&#41;</span><span class="sy0">;</span>
<span class="br0">&#125;</span></pre>
  
  <p>この例では、部分テンプレートは<code>$foo</code>と<code>$bar</code>にアクセスできるようになります。アクションがつぎのような行で終わる場合:</p>

<pre><code>  return $this-&gt;renderPartial('mymodule/mypartial', array('foo' =&gt; $this-&gt;foo));
</code></pre>
  
  <p>部分テンプレートは<code>$foo</code>にのみアクセスできるようになります。</p>
</blockquote>

<a name="components" id="components"></a><h3>コンポーネント</h3>

<p>2章において、最初のサンプルスクリプトはプレゼンテーションからロジックを分離するために2つの部分に分割されました。MVCパターンがアクションとテンプレートに適用されるように、部分テンプレートをロジックとプレゼンテーションの部分に分割する必要があるかもしれません。その場合、コンポーネント(component)を使うべきです。</p>

<p>コンポーネントは、はるかに速く動くこと以外は、アクションと似ています。コンポーネントのロジックは、<code>action/components.class.php</code>ファイルに設置された<code>sfComponents</code>から継承したクラスに保存されます。そのプレゼンテーションは部分テンプレートに保存されます。<code>sfComponents</code>クラスのメソッドは、アクションと同じように、<code>execute</code>という単語で始まり、アクションが変数を渡す方法と同じように、変数をプレゼンテーションの対応物に渡すことができます。コンポーネントに対してプレゼンテーションとして役割を果たす部分テンプレートはコンポーネントによって(先頭の<code>execute</code>ではなく、代わりにアンダースコアで)命名されます。テーブル7-1はアクションとコンポーネントの間の命名規約を比較しています。</p>

<p>テーブル7-1 - アクションとコンポーネントの命名規約</p>

<table>
<thead>
<tr>
  <th>規約</th>
  <th>アクション</th>
  <th>コンポーネント</th>
</tr>
</thead>
<tbody>
<tr>
  <td>ロジックのファイル</td>
  <td><code>actions.class.php</code></td>
  <td><code>components.class.php</code></td>
</tr>
<tr>
  <td>ロジッククラスの拡張</td>
  <td><code>sfActions</code></td>
  <td><code>sfComponents</code></td>
</tr>
<tr>
  <td>メソッドの命名方法</td>
  <td><code>executeMyAction()</code></td>
  <td><code>executeMyComponent()</code></td>
</tr>
<tr>
  <td>プレゼンテーションのファイルの命名方法</td>
  <td><code>myActionSuccess.php</code></td>
  <td><code>_myComponent.php</code></td>
</tr>
</tbody>
</table>

<blockquote class="tip"><p>
  アクションのファイルを分割できるのと同様に、<code>sfComponents</code>クラスには<code>sfAction</code>クラスに該当する<code>sfComponent</code>クラスがあり、これによりアクションと同様の構文で一ファイル一コンポーネントが可能になります。</p>
</blockquote>

<p>たとえば、任意の題目に対して最新のニュースの見出しを表示するサイドバーを持つことを仮定します。題目はユーザーのプロファイルに依存し、いくつかのページで再利用されます。ニュースの見出しを取得するために必要なクエリは単純な部分テンプレートで表示するには複雑すぎるので、これらをアクションのようなファイル、コンポーネントに移動させる必要があります。図7-3はこの例を図示しています。</p>

<p>リスト7-11と7-12で示された、この例に対して、コンポーネントは独自のモジュール(<code>news</code>)に保持されますが、ビューの機能上の観点から意味がある場合、コンポーネントとアクションを単独のモジュールに混ぜることができます。</p>

<p>図7-3 - テンプレートのなかでコンポーネントを使う</p>

<p><img src="images/F0703.png" alt="テンプレートのなかでコンポーネントを使う" title="テンプレートのなかでコンポーネントを使う" /></p>

<p>リスト7-11 - コンポーネントクラス(<code>modules/news/actions/components.class.php</code>)</p>

<pre class="php"><span class="kw2">&lt;?php</span>
&nbsp;
<span class="kw2">class</span> newsComponents <span class="kw2">extends</span> sfComponents
<span class="br0">&#123;</span>
  <span class="kw2">public</span> <span class="kw2">function</span> executeHeadlines<span class="br0">&#40;</span><span class="br0">&#41;</span>
  <span class="br0">&#123;</span>
    <span class="re0">$c</span> <span class="sy0">=</span> <span class="kw2">new</span> Criteria<span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy0">;</span>
    <span class="re0">$c</span><span class="sy0">-&gt;</span><span class="me1">addDescendingOrderByColumn</span><span class="br0">&#40;</span>NewsPeer<span class="sy0">::</span><span class="me2">PUBLISHED_AT</span><span class="br0">&#41;</span><span class="sy0">;</span>
    <span class="re0">$c</span><span class="sy0">-&gt;</span><span class="me1">setLimit</span><span class="br0">&#40;</span><span class="nu0">5</span><span class="br0">&#41;</span><span class="sy0">;</span>
    <span class="re0">$this</span><span class="sy0">-&gt;</span><span class="me1">news</span> <span class="sy0">=</span> NewsPeer<span class="sy0">::</span><span class="me2">doSelect</span><span class="br0">&#40;</span><span class="re0">$c</span><span class="br0">&#41;</span><span class="sy0">;</span>
  <span class="br0">&#125;</span>
<span class="br0">&#125;</span></pre>

<p>リスト7-12 - 部分テンプレート(<code>modules/news/templates/_headlines.php</code>)</p>

<pre class="php">&lt;div&gt;
  &lt;h1&gt;最新のニュース&lt;/h1&gt;
  &lt;ul&gt;
  <span class="kw2">&lt;?php</span> <span class="kw1">foreach</span><span class="br0">&#40;</span><span class="re0">$news</span> <span class="kw1">as</span> <span class="re0">$headline</span><span class="br0">&#41;</span><span class="sy0">:</span> <span class="sy1">?&gt;</span>
    &lt;li&gt;
      <span class="kw2">&lt;?php</span> <span class="kw1">echo</span> <span class="re0">$headline</span><span class="sy0">-&gt;</span><span class="me1">getPublishedAt</span><span class="br0">&#40;</span><span class="br0">&#41;</span> <span class="sy1">?&gt;</span>
      <span class="kw2">&lt;?php</span> <span class="kw1">echo</span> link_to<span class="br0">&#40;</span><span class="re0">$headline</span><span class="sy0">-&gt;</span><span class="me1">getTitle</span><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy0">,</span><span class="st_h">'news/show?id='</span><span class="sy0">.</span><span class="re0">$headline</span><span class="sy0">-&gt;</span><span class="me1">getId</span><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="br0">&#41;</span> <span class="sy1">?&gt;</span>
    &lt;/li&gt;
  <span class="kw2">&lt;?php</span> <span class="kw1">endforeach</span> <span class="sy1">?&gt;</span>
  &lt;/ul&gt;
&lt;/div&gt;</pre>

<p>では、コンポーネントがテンプレートのなかで必要になるたびに、つぎのように呼び出します:</p>

<pre class="php"><span class="kw2">&lt;?php</span> include_component<span class="br0">&#40;</span><span class="st_h">'news'</span><span class="sy0">,</span> <span class="st_h">'headlines'</span><span class="br0">&#41;</span> <span class="sy1">?&gt;</span></pre>

<p>部分テンプレートのように、コンポーネントは連想配列の形式で追加パラメーターを受けとります。パラメーターはこれらの名前のもとで部分テンプレート内および<code>$this</code>オブジェクトを通してコンポーネントのなかで利用できます。例としてリスト7-13をご覧ください。</p>

<p>リスト7-13 - パラメーターをコンポーネントとテンプレートに渡す</p>

<pre class="php">// コンポーネントの呼び出し
<span class="kw2">&lt;?php</span> include_component<span class="br0">&#40;</span><span class="st_h">'news'</span><span class="sy0">,</span> <span class="st_h">'headlines'</span><span class="sy0">,</span> <span class="kw3">array</span><span class="br0">&#40;</span><span class="st_h">'foo'</span> <span class="sy0">=&gt;</span> <span class="st_h">'bar'</span><span class="br0">&#41;</span><span class="br0">&#41;</span> <span class="sy1">?&gt;</span>
&nbsp;
// コンポーネント自身にて
echo $this-&gt;foo;
 =&gt; 'bar'
&nbsp;
// _headlines.php部分テンプレートのなか
echo $foo;
 =&gt; 'bar'</pre>

<p>通常のテンプレートのように、コンポーネント内部、もしくはグローバルレイアウト内部でコンポーネントをインクルードできます。アクションのように、コンポーネントの<code>execute</code>メソッドは変数を関連する部分テンプレートに渡し、同じショートカットにアクセスできます。しかし、似ている点はここまでです。コンポーネントはセキュリティもしくはバリデーションを処理せず、インターネットから呼び出すことはできませんし(呼び出せるのはアプリケーション自身からのみ)、さまざまなものを返すことはできません。それがコンポーネントがアクションよりも実行が速い理由です。</p>

<a name="slots" id="slots"></a><h3>スロット</h3>

<p>部分テンプレートとコンポーネントは再利用のために優れたものです。しかし多くの場合、コードのフラグメントは複数の動的な領域を持つレイアウトの要件を満たすことが求められます。たとえば、カスタムタグをレイアウトの<code>&lt;head&gt;</code>セクションに追加することを考えます。レイアウトはアクションの内容に依存します。もしくは、レイアウトが主要な動的な領域を1つ持つことを想定します。その領域はアクションの結果によって内容が満たされます。加えて、レイアウトは別の小さな領域をたくさん持ちます。これらの領域はレイアウトで定義されたデフォルトの内容を持ちますが、テンプレートレベルでオーバーライドできます。</p>

<p>これらの状況に対して、解決方法はスロット(slot)です。基本的には、スロットはビューの要素(レイアウト、テンプレート、もしくは部分テンプレート)に設置できるプレースホルダです。プレースホルダの内容を満たすことは変数の設定に似ています。内容を満たすコードはレスポンスにグローバルに保存されるので、どこでもスロットを定義できます(レイアウト、テンプレート、もしくは部分テンプレート)。スロットをインクルードするまえにかならずスロットを定義してください。そしてレイアウトはテンプレートのあとで実行され(これはデコレーションプロセス)、部分テンプレートがテンプレート内部に呼び出されるときに部分テンプレートが実行されることを覚えておいてください。説明が抽象的でわかりにくいですか？例を見てみましょう。</p>

<p>1つのテンプレートと2つのスロットに対して1つの領域を持つレイアウトを想像してください。1つはサイドバー用で他はフッター用です。スロットの値はテンプレート内で定義されます。デコレーションプロセスの間、図7-4に示されるように、レイアウトのコードはテンプレートのコードを包み、スロットは事まえに定義された値で満たされます。サイドバーとフッターはメインのアクションに対して文脈依存の関係があります。これは複数の"穴"をともなうレイアウトを持つことと似ています。</p>

<p>図7-4 - テンプレートのなかで定義されたレイアウトのスロット</p>

<p><img src="images/F0704.png" alt="テンプレートのなかで定義されたレイアウトのスロット" title="テンプレートのなかで定義されたレイアウトのスロット " /></p>

<p>いくつかのコードを読むことで理解が進みます。スロットを含めるには、<code>include_slot()</code>ヘルパーを使います。<code>has_slot()</code>ヘルパーはスロットが以前定義されていた場合に<code>true</code>を返します。そしておまけとしてフォールバックメカニズムを提供します。たとえば、リスト7-14で示されるように、レイアウトとデフォルトの内容のなかにある<code>'sidebar'</code>に対してプレースホルダを定義してください。</p>

<p>リスト7-14 - 'sidebar'スロットをレイアウト内部でインクルードする</p>

<pre class="php">&lt;div id=&quot;sidebar&quot;&gt;
<span class="kw2">&lt;?php</span> <span class="kw1">if</span> <span class="br0">&#40;</span>has_slot<span class="br0">&#40;</span><span class="st_h">'sidebar'</span><span class="br0">&#41;</span><span class="br0">&#41;</span><span class="sy0">:</span> <span class="sy1">?&gt;</span>
  <span class="kw2">&lt;?php</span> include_slot<span class="br0">&#40;</span><span class="st_h">'sidebar'</span><span class="br0">&#41;</span> <span class="sy1">?&gt;</span>
<span class="kw2">&lt;?php</span> <span class="kw1">else</span><span class="sy0">:</span> <span class="sy1">?&gt;</span>
  &lt;!-- default sidebar code --&gt;
  &lt;h1&gt;文脈上の領域&lt;/h1&gt;
  &lt;p&gt;この領域はページのメインの内容と関連するリンクと情報を含みます。&lt;/p&gt;
&nbsp;
<span class="kw2">&lt;?php</span> <span class="kw1">endif</span><span class="sy0">;</span> <span class="sy1">?&gt;</span>
&lt;/div&gt;</pre>

<p>スロットが定義されていない場合、デフォルトの何らかの内容を表示することはとても日常的なことなので、<code>include_slot</code>ヘルパーはスロットが定義されたどうかを示すブール値を返します。リスト7-15はコードを簡略化するためにこの戻り値を考慮する方法を示しています。</p>

<p>リスト7-15 - レイアウトのなかで<code>'sidebar'</code>スロットをインクルードする</p>

<pre class="php">&lt;div id=&quot;sidebar&quot;&gt;
<span class="kw2">&lt;?php</span> <span class="kw1">if</span> <span class="br0">&#40;</span><span class="sy0">!</span>include_slot<span class="br0">&#40;</span><span class="st_h">'sidebar'</span><span class="br0">&#41;</span><span class="br0">&#41;</span><span class="sy0">:</span> <span class="sy1">?&gt;</span>
  &lt;!-- default sidebar code --&gt;
  &lt;h1&gt;文脈依存の領域&lt;/h1&gt;
  &lt;p&gt;この領域はページのメインの内容に関連する
     リンクと情報を含みます。&lt;/p&gt;
<span class="kw2">&lt;?php</span> <span class="kw1">endif</span><span class="sy0">;</span> <span class="sy1">?&gt;</span>
&lt;/div&gt;</pre>

<p>それぞれのテンプレートはスロットの内容を定義する機能を持ちます (実際には、部分テンプレートが行います)。スロットはHTMLのコードを格納することが想定されているので、symfonyはそれらを定義する便利な方法を提供します: リスト7-16のように、<code>slot()</code>と<code>end_slot()</code>ヘルパーのあいだでスロットのコードを書くだけです。</p>

<p>リスト7-16 - テンプレートのなかで<code>'sidebar'</code>スロットの内容をオーバーライドする</p>

<pre class="php">// ...
&nbsp;
<span class="kw2">&lt;?php</span> slot<span class="br0">&#40;</span><span class="st_h">'sidebar'</span><span class="br0">&#41;</span> <span class="sy1">?&gt;</span>
  &lt;!-- 現在のテンプレートに対するカスタムサイドバーのコード --&gt;
  &lt;h1&gt;ユーザーの詳細&lt;/h1&gt;
  &lt;p&gt;名前:  <span class="kw2">&lt;?php</span> <span class="kw1">echo</span> <span class="re0">$user</span><span class="sy0">-&gt;</span><span class="me1">getName</span><span class="br0">&#40;</span><span class="br0">&#41;</span> <span class="sy1">?&gt;</span>&lt;/p&gt;
  &lt;p&gt;Eメール: <span class="kw2">&lt;?php</span> <span class="kw1">echo</span> <span class="re0">$user</span><span class="sy0">-&gt;</span><span class="me1">getEmail</span><span class="br0">&#40;</span><span class="br0">&#41;</span> <span class="sy1">?&gt;</span>&lt;/p&gt;
<span class="kw2">&lt;?php</span> end_slot<span class="br0">&#40;</span><span class="br0">&#41;</span> <span class="sy1">?&gt;</span></pre>

<p>スロットヘルパーに挟まれるコードはテンプレートのコンテキスト内で実行されるので、このコードはアクション内部で定義されたすべての変数にアクセスできます。symfonyはこのコードの結果を自動的にレスポンスオブジェクトに設置します。これはテンプレート内部では表示されませんが、リスト7-14のような、将来の<code>include_slot()</code>呼び出しに対して利用できます。</p>

<p>スロットはコンテキストの内容を表示することを目的とした領域を定義するためにとても便利です。これらは特定のアクションに対してHTMLコードをレイアウトに追加するために利用することも可能です。たとえば、最新のニュースのリストを表示するテンプレートがレイアウトの<code>&lt;head&gt;</code>部分のなかでリンクをRSSフィードに追加したい場合があります。これは<code>feed</code>スロットをレイアウトに追加してテンプレートのリストのなかでこのスロットをオーバーライドすることで簡単に実現されます。</p>

<p>スロットの内容がとても短い場合、これはまさにたとえば<code>title</code>スロットを定義する事例にあてはまります。リスト7-17で示されるように内容を<code>slot()</code>メソッドの2番目の引数として渡すことができます。</p>

<p>リスト7-17 - 短い値を定義するために<code>slot()</code>を使う</p>

<pre class="php"><span class="kw2">&lt;?php</span> slot<span class="br0">&#40;</span><span class="st_h">'title'</span><span class="sy0">,</span> <span class="st_h">'タイトルの値'</span><span class="br0">&#41;</span> <span class="sy1">?&gt;</span></pre>

<blockquote class="sidebar"><p class="title">
  <strong>テンプレートのフラグメントが見つかる場所</strong></p>
  
  <p>テンプレートにとり組む人達は通常はWebデザイナーで、symfonyについて詳しくないでしょうし、テンプレートのフラグメントはアプリケーション全体で拡散されているので、見つけることは困難でしょう。これらのいくつかのガイドラインによってsymfonyのテンプレートシステムにとり組む作業が快適になります。</p>
  
  <p>最初に、symfonyのプロジェクトは多くのディレクトリを収納していますが、すべてのレイアウト、テンプレート、テンプレートのフラグメントのファイルは<code>templates/</code>ディレクトリのなかに存在します。Webデザイナーのために、プロジェクトの構造をつぎのように小さくすることができます:</p>

<pre><code>myproject/
  apps/
    application1/
      templates/       # application 1のためのレイアウト
      modules/
        module1/
          templates/   # module 1のためのテンプレートと部分テンプレート
        module2/
          templates/   # module 2のためのテンプレートと部分テンプレート
        module3/
          templates/   # module 3のためのテンプレートと部分テンプレート
</code></pre>
  
  <p>ほかのディレクトリはすべて無視されます。</p>
  
  <p><code>include_partial()</code>に遭遇するとき、Webデザイナーは最初の引数だけが重要であることを理解する必要があります。この引数の形式は<code>module_name/partical_name</code>で、これはプレゼンテーションのコードが<code>modules/module_name/templates/_partical_name.php</code>のなかで見つかることを意味します。</p>
  
  <p><code>include_component()</code>ヘルパーに関して、最初の2つの引数はモジュールと部分テンプレートの名前です。残りに関しては、ヘルパーが何でありテンプレートのなかでもっとも共通なヘルパーはどれかといった一般的な理解をしていればsymfonyのアプリケーションのためにテンプレートの設計を始めるには十分です。</p>
</blockquote>

<a name="view.configuration" id="view.configuration"></a><h2>ビューのコンフィギュレーション</h2>

<p>symfonyにおいて、ビューは2つの相異なる部分で構成されます:</p>

<ul>
<li>アクションの結果のHTMLプレゼンテーション(テンプレート、レイアウト、そしてテンプレートフラグメントに保存される)</li>
<li><p>残りのすべて、以下の内容を含む:</p>

<ul>
<li>メタ宣言: キーワード、説明、もしくはキャッシュの持続時間 </li>
<li>ページのタイトル: あなたのサイトのページを見つけるためにいくつものウィンドウを開くユーザーに対して役立つだけでなく、サイト検索のためのインデックス作成にも非常に重要。</li>
<li>ファイルのインクルージョン: JavaScriptとスタイルシートファイル。</li>
<li>レイアウト: アクションのなかにはカスタムレイアウト(ポップアップ、広告など)を必要とするもの、もしくはレイアウトをまったく必要としないもの(Ajaxアクションなど)が存在する。</li>
</ul></li>
</ul>

<p>ビューのなかにおいて、HTMLではないすべてのものはビューの設定(コンフィギュレーション)と呼ばれ、symfonyはこれを操作するために2つの方法を提供します。通常の方法は<code>view.yml</code>設定ファイルです。このファイルは値がコンテキスト、もしくはデータベースのクエリに依存しないときはつねに使われます。動的な値を設定する必要があるとき、代わりの方法は<code>sfResponse</code>オブジェクトの属性を通してビューの設定をアクション内部で直接設定することです。</p>

<blockquote class="note"><p>
  <code>sfResponse</code>オブジェクトと<code>view.yml</code>ファイルの両方を通してビューの設定パラメーターを設定した場合、<code>sfResponse</code>の定義が優先されます。</p>
</blockquote>

<a name="the.view.yml.file" id="the.view.yml.file"></a><h3>view.ymlファイル</h3>

<p>それぞれのモジュールはビューの設定を定義する<code>view.yml</code>ファイルを1つ持つことができます。これによってモジュール全体に大してかつ単独のファイルでビューごとにビューの設定を定義できます。<code>view.yml</code>ファイルの最初のレベルのキーはモジュールのビューの名前です。リスト7-18はビューのコンフィギュレーションの例を示します。</p>

<p>リスト7-18 - モジュールレベルの<code>view.yml</code>のサンプル</p>

<pre><code>editSuccess:
  metas:
    title: プロファイルを編集する

editError:
  metas:
    title: プロファイルを編集している間に発生したエラー

all:
  stylesheets: [my_style]
  metas:
    title: 私のWebサイト
</code></pre>

<blockquote class="caution"><p>
  <code>view.yml</code>ファイルのなかのメインキーはビューの名前で、アクションの名前ではないことに注意してください。復習として、ビューの名前はアクションの名前とアクションのサフィックスによって構成されます。たとえば、<code>edit</code>アクションが<code>sfView::SUCCESS</code>を返す場合(もしくはデフォルトアクションの接尾辞であるので、何も返さない場合)、ビューの名前は<code>editSuccess</code>です。</p>
</blockquote>

<p>モジュール用のデフォルト設定はモジュールの<code>view.yml</code>の<code>all:</code>キーのもとで定義されます。すべてのアプリケーションのビューに対するデフォルト設定はアプリケーションの<code>view.yml</code>で定義されます。繰り返しますが、設定カスケードの原則を意識してください。</p>

<ul>
<li><code>apps/frontend/modules/mymodules/config/view.yml</code>において、ビュー単位の定義は1つのビューだけに適用され、モジュールレベルの定義をオーバーライドします。</li>
<li><code>apps/frontend/modules/mymodule/config/view.yml</code>において、<code>all:</code>定義はすべてのモジュールのアクションに適用され、アプリケーションレベルの定義をオーバーライドします。</li>
<li><code>apps/frontend/config/view.yml</code>において、<code>default:</code>定義はアプリケーションのすべてのモジュールとすべてのアクションに適用されます。</li>
</ul>

<blockquote class="tip"><p>
  モジュールレベルの<code>view.yml</code>ファイルはデフォルトでは存在しません。最初に、モジュール用のビュー設定パラメーターを調整する必要があり、<code>config/</code>ディレクトリのなかで空の<code>view.yml</code>を作らなければなりません。</p>
</blockquote>

<p>リスト7-5のデフォルトのテンプレートとリスト7-6の最後のレスポンスを見た後に、ヘッダーの値がどこから来るのか疑問に思うかもしれません。実際には、これらはビューのデフォルト設定であり、アプリケーションの<code>view.yml</code>で定義され、リスト7-19で示されます。</p>

<p>リスト7-19 - アプリケーションレベルのデフォルトのビュー設定(<code>apps/frontend/config/view.yml</code>)</p>

<pre><code>default:
  http_metas:
    content-type: text/html

  metas:
    #title:        symfony project
    #description:  symfony project
    #keywords:     symfony, project
    #language:     en
    robots:       index, follow

  stylesheets:    [main]

  javascripts:    []

  has_layout:     on
  layout:         layout
</code></pre>

<p>これらの設定はそれぞれ"ビューのコンフィギュレーション設定"のセクションで詳細に説明します。</p>

<a name="the.response.object" id="the.response.object"></a><h3>レスポンスオブジェクト</h3>

<p>ビューレイヤーの一部ではありますが、レスポンスオブジェクトはしばしアクションによって修正されます。アクションは<code>getResponse()</code>メソッドを通して<code>sfResponse</code>と呼ばれるsymfonyのレスポンスオブジェクトにアクセスできます。リスト7-20は、アクションのなかでよく使われる<code>sfResponse</code>メソッドのいくつかのリストを示しています。</p>

<p>リスト7-20 アクションは<code>sfResponse</code>オブジェクトメソッドにアクセスできる</p>

<pre class="php"><span class="kw2">class</span> mymoduleActions <span class="kw2">extends</span> sfActions
<span class="br0">&#123;</span>
  <span class="kw2">public</span> <span class="kw2">function</span> executeIndex<span class="br0">&#40;</span><span class="br0">&#41;</span>
  <span class="br0">&#123;</span>
    <span class="re0">$response</span> <span class="sy0">=</span> <span class="re0">$this</span><span class="sy0">-&gt;</span><span class="me1">getResponse</span><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy0">;</span>
&nbsp;
    <span class="co1">// HTTPヘッダー</span>
    <span class="re0">$response</span><span class="sy0">-&gt;</span><span class="me1">setContentType</span><span class="br0">&#40;</span><span class="st_h">'text/xml'</span><span class="br0">&#41;</span><span class="sy0">;</span>
    <span class="re0">$response</span><span class="sy0">-&gt;</span><span class="me1">setHttpHeader</span><span class="br0">&#40;</span><span class="st_h">'Content-Language'</span><span class="sy0">,</span> <span class="st_h">'en'</span><span class="br0">&#41;</span><span class="sy0">;</span>
    <span class="re0">$response</span><span class="sy0">-&gt;</span><span class="me1">setStatusCode</span><span class="br0">&#40;</span><span class="nu0">403</span><span class="br0">&#41;</span><span class="sy0">;</span>
    <span class="re0">$response</span><span class="sy0">-&gt;</span><span class="me1">addVaryHttpHeader</span><span class="br0">&#40;</span><span class="st_h">'Accept-Language'</span><span class="br0">&#41;</span><span class="sy0">;</span>
    <span class="re0">$response</span><span class="sy0">-&gt;</span><span class="me1">addCacheControlHttpHeader</span><span class="br0">&#40;</span><span class="st_h">'no-cache'</span><span class="br0">&#41;</span><span class="sy0">;</span>
&nbsp;
    <span class="co1">// Cookie</span>
    <span class="re0">$response</span><span class="sy0">-&gt;</span><span class="me1">setCookie</span><span class="br0">&#40;</span><span class="re0">$name</span><span class="sy0">,</span> <span class="re0">$content</span><span class="sy0">,</span> <span class="re0">$expire</span><span class="sy0">,</span> <span class="re0">$path</span><span class="sy0">,</span> <span class="re0">$domain</span><span class="br0">&#41;</span><span class="sy0">;</span>
&nbsp;
    <span class="co1">// メタ情報とページのヘッダー</span>
    <span class="re0">$response</span><span class="sy0">-&gt;</span><span class="me1">addMeta</span><span class="br0">&#40;</span><span class="st_h">'robots'</span><span class="sy0">,</span> <span class="st_h">'NONE'</span><span class="br0">&#41;</span><span class="sy0">;</span>
    <span class="re0">$response</span><span class="sy0">-&gt;</span><span class="me1">addMeta</span><span class="br0">&#40;</span><span class="st_h">'keywords'</span><span class="sy0">,</span> <span class="st_h">'foo bar'</span><span class="br0">&#41;</span><span class="sy0">;</span>
    <span class="re0">$response</span><span class="sy0">-&gt;</span><span class="me1">setTitle</span><span class="br0">&#40;</span><span class="st_h">'My FooBar Page'</span><span class="br0">&#41;</span><span class="sy0">;</span>
    <span class="re0">$response</span><span class="sy0">-&gt;</span><span class="me1">addStyleSheet</span><span class="br0">&#40;</span><span class="st_h">'custom_style'</span><span class="br0">&#41;</span><span class="sy0">;</span>
    <span class="re0">$response</span><span class="sy0">-&gt;</span><span class="me1">addJavaScript</span><span class="br0">&#40;</span><span class="st_h">'custom_behavior'</span><span class="br0">&#41;</span><span class="sy0">;</span>
  <span class="br0">&#125;</span>
<span class="br0">&#125;</span></pre>

<p>ここで示されるセッターメソッドに加えて、<code>sfReponse</code>クラスはレスポンス属性の現在の値を返すゲッターを持ちます。</p>

<p>symfonyではヘッダーのセッターはとても強力です。(<code>sfRenderingFilter</code>で)ヘッダーは可能なかぎり遅く送信されるので、望むだけ多く、そして遅く変更することができます。それらはとても便利なショートカットも提供します。たとえば、<code>setContentType()</code>を呼び出すときにcharsetを指定できない場合、symfonyは<code>settings.yml</code>ファイルで定義されたデフォルトのcharsetを自動的に追加します。</p>

<pre class="php"><span class="re0">$response</span><span class="sy0">-&gt;</span><span class="me1">setContentType</span><span class="br0">&#40;</span><span class="st_h">'text/xml'</span><span class="br0">&#41;</span><span class="sy0">;</span>
<span class="kw1">echo</span> <span class="re0">$response</span><span class="sy0">-&gt;</span><span class="me1">getContentType</span><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy0">;</span>
 <span class="sy0">=&gt;</span> <span class="st_h">'text/xml; charset=utf-8'</span></pre>

<p>symfonyのレスポンスのステータスコードはHTTPの仕様と互換性があります。例外の場合はステータス500を返し、ページが見つからない場合はステータス404を返し、通常のページの場合はステータス200を返し、修正されていないページの場合はステータス304と共にシンプルなヘッダーに減らすことができます(詳細は12章を参照)。しかし、<code>setStatusCode()</code>レスポンスメソッドを持つアクションのなかで独自のステータスコードを設定することで、これらのデフォルトをオーバーライドできます。カスタムコードとメッセージ、もしくは単なるカスタムコードを指定できます。この場合、symfonyはこのコードに対してもっとも共通したメッセージを追加します。</p>

<pre class="php"><span class="re0">$response</span><span class="sy0">-&gt;</span><span class="me1">setStatusCode</span><span class="br0">&#40;</span><span class="nu0">404</span><span class="sy0">,</span> <span class="st_h">'このページは存在しません'</span><span class="br0">&#41;</span><span class="sy0">;</span></pre>

<blockquote class="tip"><p>
  ヘッダーを送るまえに、symfonyはこれらの名前を正規化します。<code>setHttpHeader()</code>呼び出しのなかで<code>Contetn-Language</code>の代わりに<code>content-language</code>を書くことに悩む必要はありません。syfmonyは前者を理解し、自動的に後者に変換するからです。</p>
</blockquote>

<a name="view.configuration.settings" id="view.configuration.settings"></a><h3>ビューのコンフィギュレーション設定</h3>

<p>2種類のビューのコンフィギュレーション設定があることにお気づきかもしれません:</p>

<ul>
<li>ユニークな値を持つもの(値は<code>view.yml</code>ファイルのなかの文字列で、レスポンスはそれらに対して<code>set</code>メソッドを使う)</li>
<li>複数の値を持つもの(<code>view.yml</code>は配列を使い、レスポンスは<code>add</code>メソッドを使う)</li>
</ul>

<p>設定カスケードはユニークな値の設定を削除し複数の値の設定を集積することを覚えておいてください。この章を読み進めればあきらかになります。</p>

<a name="meta.tag.configuration" id="meta.tag.configuration"></a><h3>メタタグのコンフィギュレーション</h3>

<p>レスポンスの<code>&lt;meta&gt;</code>タグに書かれた情報はブラウザーには表示されませんが、ロボットと検索エンジンには役立ちます。これはすべてのページのキャッシュ設定もコントロールします。リスト7-19のように、これらのタグは<code>view.ymlのなかの</code>http_metas:<code>と</code>metas:<code>キーの下で定義するか、リスト7-21のように、アクションの</code>addHttpMeta()<code>と</code>addMeta()`レスポンスメソッドでこれらのタグを定義します。</p>

<p>リスト7-21 - <code>view.yml</code>のなかの「キー: 値」の組としてのメタの定義</p>

<pre><code>http_metas:
  cache-control: public

metas:
  description:   Finance in France
  keywords:      finance, France
</code></pre>

<p>リスト7-22 - レスポンスアクションのレスポンス設定としてのメタの定義</p>

<pre class="php"><span class="re0">$this</span><span class="sy0">-&gt;</span><span class="me1">getResponse</span><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy0">-&gt;</span><span class="me1">addHttpMeta</span><span class="br0">&#40;</span><span class="st_h">'cache-control'</span><span class="sy0">,</span> <span class="st_h">'public'</span><span class="br0">&#41;</span><span class="sy0">;</span>
<span class="re0">$this</span><span class="sy0">-&gt;</span><span class="me1">getResponse</span><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy0">-&gt;</span><span class="me1">addMeta</span><span class="br0">&#40;</span><span class="st_h">'description'</span><span class="sy0">,</span> <span class="st_h">'Finance in France'</span><span class="br0">&#41;</span><span class="sy0">;</span>
<span class="re0">$this</span><span class="sy0">-&gt;</span><span class="me1">getResponse</span><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy0">-&gt;</span><span class="me1">addMeta</span><span class="br0">&#40;</span><span class="st_h">'keywords'</span><span class="sy0">,</span> <span class="st_h">'finance, France'</span><span class="br0">&#41;</span><span class="sy0">;</span></pre>

<p>デフォルトでは既存のキーを追加すると現在の内容が置き換えられます。HTTPメタタグに対して、<code>addHttpMeta()</code>メソッド(<code>setHttpHeader()</code>も同様)は3番目の値を設定することができ、falseを指定した場合は既存の値を置き換えるのではなく値を追加します。</p>

<pre class="php"><span class="re0">$this</span><span class="sy0">-&gt;</span><span class="me1">getResponse</span><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy0">-&gt;</span><span class="me1">addHttpMeta</span><span class="br0">&#40;</span><span class="st_h">'accept-language'</span><span class="sy0">,</span> <span class="st_h">'en'</span><span class="br0">&#41;</span><span class="sy0">;</span>
<span class="re0">$this</span><span class="sy0">-&gt;</span><span class="me1">getResponse</span><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy0">-&gt;</span><span class="me1">addHttpMeta</span><span class="br0">&#40;</span><span class="st_h">'accept-language'</span><span class="sy0">,</span> <span class="st_h">'fr'</span><span class="sy0">,</span> <span class="kw4">false</span><span class="br0">&#41;</span><span class="sy0">;</span>
<span class="kw1">echo</span> <span class="re0">$this</span><span class="sy0">-&gt;</span><span class="me1">getResponse</span><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy0">-&gt;</span><span class="me1">getHttpHeader</span><span class="br0">&#40;</span><span class="st_h">'accept-language'</span><span class="br0">&#41;</span><span class="sy0">;</span>
 <span class="sy0">=&gt;</span> <span class="st_h">'en, fr'</span></pre>

<p>これらのメタタグが最終的なドキュメントに表示されるように、<code>include_http_metas()</code>と<code>include_metas()</code>ヘルパーは<code>&lt;head&gt;</code>セクションのなかで呼び出されなければなりません(これはデフォルトのレイアウトの場合; リスト7-5を参照)。適切な<code>&lt;meta&gt;</code>タグを出力するためにsymfonyはすべての<code>view.yml</code>ファイル(リスト7-18で示されているデフォルトのものを含む)とレスポンス属性から自動的に設定を集約します。リスト7-21の例はリスト7-23で示されているような状態で終わります。</p>

<p>リスト7-23 - 最終的なページのメタタグの出力</p>

<pre class="php"><span class="sy0">&lt;</span>meta http<span class="sy0">-</span>equiv<span class="sy0">=</span><span class="st0">&quot;content-type&quot;</span> content<span class="sy0">=</span><span class="st0">&quot;text/html; charset=utf-8&quot;</span> <span class="sy0">/&gt;</span>
<span class="sy0">&lt;</span>meta http<span class="sy0">-</span>equiv<span class="sy0">=</span><span class="st0">&quot;cache-control&quot;</span> content<span class="sy0">=</span><span class="st0">&quot;public&quot;</span> <span class="sy0">/&gt;</span>
<span class="sy0">&lt;</span>meta name<span class="sy0">=</span><span class="st0">&quot;robots&quot;</span> content<span class="sy0">=</span><span class="st0">&quot;index, follow&quot;</span> <span class="sy0">/&gt;</span>
<span class="sy0">&lt;</span>meta name<span class="sy0">=</span><span class="st0">&quot;description&quot;</span> content<span class="sy0">=</span><span class="st0">&quot;Finance in France&quot;</span> <span class="sy0">/&gt;</span>
<span class="sy0">&lt;</span>meta name<span class="sy0">=</span><span class="st0">&quot;keywords&quot;</span> content<span class="sy0">=</span><span class="st0">&quot;finance, France&quot;</span> <span class="sy0">/&gt;</span></pre>

<p>おまけとして、レスポンスのHTTPヘッダーは、レイアウトに<code>include_http_metas()</code>ヘルパーが存在しないもしくはレイアウトがまったくない場合、<code>http-metas:</code>の定義にも影響されます。たとえば、ページをプレーンテキストとして送る必要がある場合、つぎのように<code>view.yml</code>を定義します:</p>

<pre><code>http_metas:
  content-type: text/plain

has_layout: false
</code></pre>

<a name="title.configuration" id="title.configuration"></a><h3>タイトルのコンフィギュレーション</h3>

<p>ページタイトルは検索エンジンのインデックス作業の重要な部分です。タブ機能を提供するモダンなブラウザーでも非常に便利です。HTMLにおいて、タイトルはページのタグとメタの両方の情報であるので、<code>view.yml</code>ファイルは<code>title:</code>キーを<code>metas:</code>キーの子として探します。リスト7-24は<code>view.yml</code>のタイトル定義を示し、リスト7-25はアクション定義を示します。</p>

<p>リスト7-24 - <code>view.yml</code>のタイトル定義</p>

<pre><code>indexSuccess:
  metas:
    title: Three little piggies
</code></pre>

<p>リスト7-25 - アクションのなかのタイトルの定義 -- 動的なタイトルを可能にする</p>

<pre class="php"><span class="re0">$this</span><span class="sy0">-&gt;</span><span class="me1">getResponse</span><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy0">-&gt;</span><span class="me1">setTitle</span><span class="br0">&#40;</span><span class="kw3">sprintf</span><span class="br0">&#40;</span><span class="st_h">'%d little piggies'</span><span class="sy0">,</span> <span class="re0">$number</span><span class="br0">&#41;</span><span class="br0">&#41;</span><span class="sy0">;</span></pre>

<p>最終的なドキュメントの<code>&lt;head&gt;</code>セクションにおいて、<code>&lt;title&gt;</code>タグタイトルの定義は、<code>include_metas()</code>ヘルパーが存在する場合は<code>&lt;meta name="title"&gt;</code>タグを、<code>include_title()</code>ヘルパーが存在する場合は<code>&lt;title&gt;</code>タグを設定します。両ほうが含まれる場合(リスト7-5のデフォルトのレイアウトなど)、タイトルはドキュメントのソース内で2回表示されますが(リスト7-6を参照)、これは無害です。</p>

<a name="file.inclusion.configuration" id="file.inclusion.configuration"></a><h3>ファイルのインクルードコンフィギュレーション</h3>

<p>リスト7-26が示すように、特定のスタイルシートもしくはJavaScriptファイルをビューに追加することは簡単です。</p>

<p>リスト7-26 - アセットファイルのインクルード</p>

<pre><code>// view.ymlのなかで
indexSuccess:
  stylesheets: [mystyle1, mystyle2]
  javascripts: [myscript]

// アクションのなかで
$this-&gt;getResponse()-&gt;addStylesheet('mystyle1');
$this-&gt;getResponse()-&gt;addStylesheet('mystyle2');
$this-&gt;getResponse()-&gt;addJavascript('myscript');

// テンプレートのなかで
&lt;?php use_stylesheet('mystyle1') ?&gt;
&lt;?php use_stylesheet('mystyle2') ?&gt;
&lt;?php use_javascript('myscript') ?&gt;
</code></pre>

<p>それぞれの場合、引数はファイル名です。ファイルが正しい拡張子を持つ場合(<code>.css</code>はスタイルシート、<code>.js</code>はJavaScriptファイル)、これを省略することができます。ファイルが正しい位置(<code>/css/</code>はスタイルシート、<code>/js/</code>はJavaScriptファイル)にある場合、同様に省略できます。symfonyは正しい拡張子、もしくは位置を理解するぐらい十分に賢いです。</p>

<p>メタとタイトルの定義とは異なり、ファイルのインクルード定義はテンプレートのヘルパーもしくは含まれるレイアウトを必要としません。このことは以前の設定はテンプレートとレイアウトの内容が何であれ、リスト7-27のHTMLコードを出力することを意味します。</p>

<p>リスト7-27 - ファイルのインクルードの結果 -- レイアウトのなかではヘルパーの呼び出しに必要ない</p>

<pre class="php"><span class="sy0">&lt;</span>head<span class="sy0">&gt;</span>
<span class="sy0">...</span>
<span class="sy0">&lt;</span>link rel<span class="sy0">=</span><span class="st0">&quot;stylesheet&quot;</span> type<span class="sy0">=</span><span class="st0">&quot;text/css&quot;</span> media<span class="sy0">=</span><span class="st0">&quot;screen&quot;</span> href<span class="sy0">=</span><span class="st0">&quot;/css/mystyle1.css&quot;</span> <span class="sy0">/&gt;</span>
<span class="sy0">&lt;</span>link rel<span class="sy0">=</span><span class="st0">&quot;stylesheet&quot;</span> type<span class="sy0">=</span><span class="st0">&quot;text/css&quot;</span> media<span class="sy0">=</span><span class="st0">&quot;screen&quot;</span> href<span class="sy0">=</span><span class="st0">&quot;/css/mystyle2.css&quot;</span> <span class="sy0">/&gt;</span>
<span class="kw2">&lt;script language</span><span class="sy0">=</span><span class="st0">&quot;javascript&quot;</span> type<span class="sy0">=</span><span class="st0">&quot;text/javascript&quot;</span> src<span class="sy0">=</span><span class="st0">&quot;/js/myscript.js&quot;</span><span class="sy0">&gt;</span>
<span class="kw2">&lt;/script&gt;</span>
<span class="sy0">&lt;/</span>head<span class="sy0">&gt;</span></pre>

<blockquote class="note"><p>
  レスポンスではスタイルシートとJavaScriptのインクルードは<code>sfCommonFilter</code>という名前のフィルターによって実行されます。これはレスポンスの<code>&lt;head&gt;</code>タグを探し、<code>&lt;/head&gt;</code>を丁度閉じるまえに<code>&lt;link&gt;</code>タグと<code>&lt;script&gt;</code>タグを追加します。レイアウトもしくはテンプレートのなかに<code>&lt;head&gt;</code>タグが存在しない場合、インクルードが行われないことを意味します。</p>
</blockquote>

<p>設定カスケードの原則が適用されるので、アプリケーションの<code>view.yml</code>のなかで定義された任意のファイルインクルードはアプリケーションのすべてのページで現れます。リスト7-28、7-29、7-30はこの原則のお手本を示しています。</p>

<p>リスト7-28 - アプリケーションの<code>view.yml</code>のサンプル</p>

<pre><code>default:
  stylesheets: [main]
</code></pre>

<p>リスト7-29 - モジュールの<code>view.yml</code>のサンプル</p>

<pre><code>indexSuccess:
  stylesheets: [special]

all:
  stylesheets: [additional]
</code></pre>

<p>リスト7-30 - <code>indexSuccess</code>ビューの結果</p>

<pre class="php"><span class="sy0">&lt;</span>link rel<span class="sy0">=</span><span class="st0">&quot;stylesheet&quot;</span> type<span class="sy0">=</span><span class="st0">&quot;text/css&quot;</span> media<span class="sy0">=</span><span class="st0">&quot;screen&quot;</span> href<span class="sy0">=</span><span class="st0">&quot;/css/main.css&quot;</span> <span class="sy0">/&gt;</span>
<span class="sy0">&lt;</span>link rel<span class="sy0">=</span><span class="st0">&quot;stylesheet&quot;</span> type<span class="sy0">=</span><span class="st0">&quot;text/css&quot;</span> media<span class="sy0">=</span><span class="st0">&quot;screen&quot;</span> href<span class="sy0">=</span><span class="st0">&quot;/css/additional.css&quot;</span> <span class="sy0">/&gt;</span>
<span class="sy0">&lt;</span>link rel<span class="sy0">=</span><span class="st0">&quot;stylesheet&quot;</span> type<span class="sy0">=</span><span class="st0">&quot;text/css&quot;</span> media<span class="sy0">=</span><span class="st0">&quot;screen&quot;</span> href<span class="sy0">=</span><span class="st0">&quot;/css/special.css&quot;</span> <span class="sy0">/&gt;</span></pre>

<p>より高いレベルで定義されたファイルを除外することが必要がある場合、リスト7-31で示されるように、より低いレベルの定義で、マイナス記号(<code>-</code>)をファイルの名前のまえに追加します。</p>

<p>リスト7-31 - サンプルモジュールの<code>view.yml</code>はアプリケーションレベルで定義されたファイルをとり除く</p>

<pre><code>indexSuccess:
  stylesheets: [-main, special]

all:
  stylesheets: [additional]
</code></pre>

<p>すべてのスタイルシートもしくはJavaScriptファイルを除外するには、リスト7-32で示されるように、<code>-*</code>をファイル名として使います。</p>

<p>リスト7-32 - アプリケーションレベルで定義されるすべてのファイルを除外するモジュールの<code>view.yml</code>のサンプル</p>

<pre><code>indexSuccess:
  stylesheets: [-*]
  javascripts: [-*]
</code></pre>

<p>リスト7-33で示されるように、ファイルをインクルードする位置(最初もしくは最後の位置)を強制するためにより正確な追加のパラメーターを定義することができます。これはスタイルシートとJavaScriptの両方に対して機能にします。</p>

<p>リスト7-33 - インクルードされるアセットの位置を定義する</p>

<pre><code>// view.ymlのなか
indexSuccess:
  stylesheets: [special: { position: first }]

// アクションのなか
$this-&gt;getResponse()-&gt;addStylesheet('special', 'first');

// テンプレートのなか
&lt;?php use_stylesheet('special', 'first') ?&gt;
</code></pre>

<p><strong>symfony 1.1の新しい機能</strong>: リスト7-34で示されるように、結果の<code>&lt;link&gt;</code>もしくは<code>&lt;script&gt;</code>のタグが正しい指定位置を参照するように、アセットファイル名の変形を回避することを決めることもできます。</p>

<p>リスト7-34 - そのままの名前でスタイルシートをインクルードする</p>

<pre><code>// view.ymlのなか
indexSuccess:
  stylesheets: [main, paper: { raw_name: true }]

// アクションのなか
$this-&gt;getResponse()-&gt;addStylesheet('main', '', array('raw_name' =&gt; true));

// テンプレートのなか
&lt;?php use_stylesheet('main', '', array('raw_name' =&gt; true)) ?&gt;

// ビューの結果
&lt;link rel="stylesheet" type="text/css" media="print" href="main" /&gt;
</code></pre>

<p>リスト7-35で示されるように、スタイルシートのインクルードに対してmediaを指定するために、スタイルシートのタグのデフォルトオプションを変更できます。</p>

<p>リスト7-35 - mediaを指定してスタイルシートをインクルードする</p>

<pre><code>// view.ymlのなかで
indexSuccess:
  stylesheets: [main, paper: { media: print }]

// アクションのなかで
$this-&gt;getResponse()-&gt;addStylesheet('paper', '', array('media' =&gt; 'print'));

// テンプレートのなかで
&lt;?php use_stylesheet('paper', '', array('media' =&gt; 'print')) ?&gt;

// 結果のビュー
&lt;link rel="stylesheet" type="text/css" media="print" href="/css/paper.css" /&gt;
</code></pre>

<a name="layout.configuration" id="layout.configuration"></a><h3>レイアウトのコンフィギュレーション</h3>

<p>Webサイトではグラフィカルな表にしたがってレイアウトが複数存在します。古典的なWebサイトは少なくとも2つ持ちます: デフォルトのレイアウトとポップアップのレイアウトです。</p>

<p>デフォルトのレイアウトが<code>myproject/apps/frontend/templates/layout.php</code>であることはすでに見ました。追加のレイアウトは同じグローバルな<code>templates/</code>ディレクトリに追加しなければなりません。<code>frontend/templates/my_layout.php</code>ファイルでビューが欲しい場合、リスト7-36で示されるつぎの構文を使います。</p>

<p>リスト7-36 - レイアウトの定義</p>

<pre><code>// view.ymlのなかで
indexSuccess:
  layout: my_layout

// アクションのなかで
$this-&gt;setLayout('my_layout');

// テンプレートのなかで
&lt;?php decorate_with('my_layout') ?&gt;
</code></pre>

<p>ビューのなかにはレイアウトがまったく必要のないものがあります(たとえば、RSSフィード上のプレーンテキストのページ)。この場合、リスト7-37で示されるように、<code>has_layout</code>を<code>false</code>に設定してください。</p>

<p>リスト7-37 - レイアウトの除去</p>

<pre><code>// `view.yml`のなかで
indexSuccess:
  has_layout: false

// アクションのなかで
$this-&gt;setLayout(false);

// テンプレートのなかで
&lt;?php decorate_with(false) ?&gt;
</code></pre>

<blockquote class="note"><p>
  デフォルトではAjaxのアクションのビューはレイアウトを持ちません。</p>
</blockquote>

<a name="component.slots" id="component.slots"></a><h2>コンポーネントスロット</h2>

<p>ビューのコンポーネントとビューの設定の力を組み合わせることでビューの開発に新しい観点がもたらされます: コンポーネントスロット(component slot)システムです。再利用性とレイヤーの分離に焦点を当てるスロットの代替物です。ですので、コンポーネントスロットはスロットよりも構造的ですが、実行は少し遅いです。</p>

<p>スロットのように、コンポーネントスロットはビューの要素内で宣言できる名前つきのプレースホルダーです。違いは入力コードを決定する方法にあります。スロットに対して、コードは別のビューの要素のなかに設定されます; コンポーネントスロットに対して、コードはコンポーネントの実行から由来し、このコンポーネントの名前はビューの設定から由来します。アクションのなかでコンポーネントスロットを見た後にこれらの理解がより深まります。</p>

<p>コンポーネントスロットのプレースホルダーを設定するには、<code>include_component_slot()</code>ヘルパーを使います。この関数はパラメーターとしてラベルを必要とします。たとえば、アプリケーションの<code>layout.php</code>ファイルがコンテキスト上のサイドバーを含む場合を想像してください。リスト7-38はコンポーネントスロットのヘルパーがインクルードされる方法を示しています。</p>

<p>リスト7-38 - 'sidebar'という名前のコンポーネントスロットをインクルードする</p>

<pre class="php">...
&lt;div id=&quot;sidebar&quot;&gt;
  <span class="kw2">&lt;?php</span> include_component_slot<span class="br0">&#40;</span><span class="st_h">'sidebar'</span><span class="br0">&#41;</span> <span class="sy1">?&gt;</span>
&lt;/div&gt;</pre>

<p>コンポーネントスロットのラベルとコンポーネントの名前の間の対応をビューの設定のなかで定義します。たとえば、アプリケーションの<code>view.yml</code>で、<code>components</code>ヘッダーの下の<code>sidebar</code>コンポーネントでデフォルトのコンポーネントを設定します。キーはコンポーネントスロットのラベルです; 値はモジュールとコンポーネントの名前を含む配列でなければなりません。リスト7-39は例を示しています。</p>

<p>リスト7-39 - デフォルトの'sidebar'コンポーネントスロットを定義する(<code>frontend/config/view.yml</code>)</p>

<pre><code>default:
  components:
    sidebar:  [bar, default]
</code></pre>

<p>レイアウトが実行されたとき、<code>sidebar</code>コンポーネントスロットは<code>bar</code>モジュールに設置された<code>barComponents</code>クラスの<code>executeDefault()</code>メソッドの結果で内容が満たされ、このメソッドは<code>modules/bar/templates/</code>に設置された<code>_default.php</code>部分テンプレートを表示します。</p>

<p>設定カスケードによって任意のモジュールに対してこの設定をオーバーライドできます。たとえば、<code>user</code>モジュールにおいて、ユーザー名とユーザーが公開した記事の数を表示するコンテキスト上のコンポーネントが欲しいことがあります。この場合、リスト7-40で示されるように、モジュールの<code>view.yml</code>のなかでサイドバースロットの設定を特化します。</p>

<p>リスト7-40 - 'sidebar'スロットコンポーネントを特化する(<code>frontend/modules/user/config/view.yml</code>)</p>

<pre><code>all:
  components:
    sidebar:  [bar, user]
</code></pre>

<p>このスロットを処理するコンポーネントの定義はリスト7-41のようなものになります。</p>

<p>リスト7-41 - 'sidebar'スロットによって使われるコンポーネント(<code>modules/bar/actions/components.class.php</code>)</p>

<pre class="php"><span class="kw2">class</span> barComponents <span class="kw2">extends</span> sfComponents
<span class="br0">&#123;</span>
  <span class="kw2">public</span> <span class="kw2">function</span> executeDefault<span class="br0">&#40;</span><span class="br0">&#41;</span>
  <span class="br0">&#123;</span>
  <span class="br0">&#125;</span>
&nbsp;
  <span class="kw2">public</span> <span class="kw2">function</span> executeUser<span class="br0">&#40;</span><span class="br0">&#41;</span>
  <span class="br0">&#123;</span>
    <span class="re0">$this</span><span class="sy0">-&gt;</span><span class="me1">current_user</span> <span class="sy0">=</span> <span class="re0">$this</span><span class="sy0">-&gt;</span><span class="me1">getUser</span><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy0">-&gt;</span><span class="me1">getCurrentUser</span><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy0">;</span>
    <span class="re0">$c</span> <span class="sy0">=</span> <span class="kw2">new</span> Criteria<span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy0">;</span>
    <span class="re0">$c</span><span class="sy0">-&gt;</span><span class="me1">add</span><span class="br0">&#40;</span>ArticlePeer<span class="sy0">::</span><span class="me2">AUTHOR_ID</span><span class="sy0">,</span> <span class="re0">$this</span><span class="sy0">-&gt;</span><span class="me1">current_user</span><span class="sy0">-&gt;</span><span class="me1">getId</span><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="br0">&#41;</span><span class="sy0">;</span>
    <span class="re0">$this</span><span class="sy0">-&gt;</span><span class="me1">nb_articles</span> <span class="sy0">=</span> ArticlePeer<span class="sy0">::</span><span class="me2">doCount</span><span class="br0">&#40;</span><span class="re0">$c</span><span class="br0">&#41;</span><span class="sy0">;</span>
  <span class="br0">&#125;</span>
<span class="br0">&#125;</span></pre>

<p>リスト7-42はこれら2つのコンポーネントのためのビューを示しています。</p>

<p>リスト7-42 - 'sidebar'スロットコンポーネントによって使われる部分テンプレート(<code>modules/bar/templates/</code>)</p>

<pre class="php">// _default.php
&lt;p&gt;この領域はコンテキスト上の情報を含みます。&lt;/p&gt;
&nbsp;
// _user.php
&lt;p&gt;ユーザー名: <span class="kw2">&lt;?php</span> <span class="kw1">echo</span> <span class="re0">$current_user</span><span class="sy0">-&gt;</span><span class="me1">getName</span><span class="br0">&#40;</span><span class="br0">&#41;</span> <span class="sy1">?&gt;</span>&lt;/p&gt;
&lt;p&gt;<span class="kw2">&lt;?php</span> <span class="kw1">echo</span> <span class="re0">$nb_articles</span> <span class="sy1">?&gt;</span> articles published&lt;/p&gt;</pre>

<p>コンポーネントスロットはパンくずリスト、コンテキスト上のナビゲーション、あらゆる種類の動的な挿入のために使われます。コンポーネントとして、これらはグローバルレイアウトと通常のテンプレート、もしくはほかのコンポーネントのなかで使えます。スロットのコンポーネントを設定するコンフィギュレーションは最後に呼び出されたアクションのコンフィギュレーションからつねに除外されます。</p>

<p>任意のモジュールに対してコンポーネントスロットの利用を一時中止する必要がある場合、リスト7-43で示されるように、空のモジュール/コンポーネントを宣言します。</p>

<p>リスト7-43 - コンポーネントスロットを無効にする(<code>view.yml</code>)</p>

<pre><code>all:
  components:
    sidebar:  []
</code></pre>

<a name="output.escaping" id="output.escaping"></a><h2>出力エスケーピング機能</h2>

<p>動的なデータをテンプレートに挿入するとき、データの統合性について気をつけなければなりません。たとえば、データが匿名ユーザーから入力されたフォームから来た場合、クロスサイトスクリプティング(XSS - Cross-Site Scripting)攻撃を開始する悪意のあるスクリプトを含んでいるリスクがあります。出力データに含まれるHTMLタグが無害になるように、出力データをエスケープできることが必須です。</p>

<p>例として、ユーザーが入力フィールドをつぎのような値で満たすことを想像してください:</p>

<pre class="php"><span class="sy0">&lt;</span>script<span class="sy0">&gt;</span>alert<span class="br0">&#40;</span>document<span class="sy0">.</span>cookie<span class="br0">&#41;</span><span class="kw2">&lt;/script&gt;</span></pre>

<p>警告なしでこの値をechoする場合、JavaScriptはすべてのブラウザーで実行され、アラートを表示するよりはるかに危険な攻撃を許してしまいます。値をつぎのように変換するために、表示まえに値をエスケープしなければならない理由はそういうわけです:</p>

<pre class="php"><span class="sy0">&amp;</span>lt<span class="sy0">;</span>script<span class="sy0">&amp;</span>gt<span class="sy0">;</span>alert<span class="br0">&#40;</span>document<span class="sy0">.</span>cookie<span class="br0">&#41;</span><span class="sy0">&amp;</span>lt<span class="sy0">;/</span>script<span class="sy0">&amp;</span>gt<span class="sy0">;</span></pre>

<p><code>htmlspecialchars()</code>の呼び出しで信頼性のないすべての値を囲むことで出力を手動でエスケープできますが、このアプローチは繰り返し作業がとても多くエラーが起こりやすいです。代わりにsymfonyは出力エスケーピング(output escaping)と呼ばれる特別なシステムを提供します。これはテンプレート内のすべての変数出力を自動的にエスケープします。これはアプリケーションの<code>settings.yml</code>の単純なパラメーターで有効になります。</p>

<a name="activating.output.escaping" id="activating.output.escaping"></a><h3>出力エスケーピング機能を有効にする</h3>

<p>出力エスケーピング機能は<code>settings.yml</code>のなかでアプリケーションに対してグローバルに設定されます。2つのパラメーターが出力エスケーピングのふるまいをコントロールします: エスケーピング戦略(<code>escaping_strategy</code>)がビューのなかで変数を利用できるようにする方法を決定し、エスケーピングメソッド(<code>escaping_method</code>)はデータに適用されるデフォルトのエスケーピング機能です。</p>

<p>基本的に、出力エスケーピング機能を有効にするために必要なことは、リスト7-42で示されるように、<code>escaping_strategy</code>パラメーターの値をデフォルトの<code>off</code>の代わりに<code>on</code>にセットすることです。</p>

<p>リスト7-42 - 出力エスケーピング機能を有効にする(<code>frontend/config/settings.yml</code>)</p>

<pre><code>all:
  .settings:
    escaping_strategy: on
    escaping_method:   ESC_SPECIALCHARS
</code></pre>

<p>デフォルトではこれはすべての変数の出力に<code>htmlspeciachars()</code>を追加します。たとえば、つぎのようにアクションで<code>test</code>変数を定義することを想像してみましょう:</p>

<pre class="php"><span class="re0">$this</span><span class="sy0">-&gt;</span><span class="me1">test</span> <span class="sy0">=</span> <span class="st_h">'&lt;script&gt;alert(document.cookie)&lt;/script&gt;'</span><span class="sy0">;</span></pre>

<p>出力エスケーピング機能を有効にした場合、この変数をテンプレートのなかでechoするとエスケープされたデータが出力されます:</p>

<pre class="php"><span class="kw1">echo</span> <span class="re0">$test</span><span class="sy0">;</span>
 <span class="sy0">=&gt;</span> <span class="sy0">&amp;</span>lt<span class="sy0">;</span>script<span class="sy0">&amp;</span>gt<span class="sy0">;</span>alert<span class="br0">&#40;</span>document<span class="sy0">.</span>cookie<span class="br0">&#41;</span><span class="sy0">&amp;</span>lt<span class="sy0">;/</span>script<span class="sy0">&amp;</span>gt<span class="sy0">;</span></pre>

<p>また、すべてのテンプレートは<code>$sf_data</code>変数にアクセスできます。これはエスケープされたすべての変数を参照するコンテナオブジェクトです。ですのでつぎのように<code>test</code>変数を出力することもできます:</p>

<pre class="php"><span class="kw1">echo</span> <span class="re0">$sf_data</span><span class="sy0">-&gt;</span><span class="me1">get</span><span class="br0">&#40;</span><span class="st_h">'test'</span><span class="br0">&#41;</span><span class="sy0">;</span>
<span class="sy0">=&gt;</span> <span class="sy0">&amp;</span>lt<span class="sy0">;</span>script<span class="sy0">&amp;</span>gt<span class="sy0">;</span>alert<span class="br0">&#40;</span>document<span class="sy0">.</span>cookie<span class="br0">&#41;</span><span class="sy0">&amp;</span>lt<span class="sy0">;/</span>script<span class="sy0">&amp;</span>gt<span class="sy0">;</span></pre>

<blockquote class="tip"><p>
  <code>$sf_data</code>オブジェクトはArrayインターフェイスを実装するので、<code>$sf_data-&gt;get('myvariable')</code>を使う代わりに、<code>$sf_data['myvariable']</code>を呼び出すことでエスケープされた値をとり出すことができます。しかし、これは本当の配列ではないので、<code>print_r()</code>のような関数は期待どおりに動きません。</p>
</blockquote>

<p><code>$sf_data</code>によってエスケープされていないもしくは生データにもアクセスできます。変数を信用することが前提になりますが、このことは変数がブラウザーに解釈されること想定したHTMLコードを保存するときに便利です。生データを出力することが必要なとき、<code>getRaw()</code>メソッドを呼び出します。</p>

<pre class="php"><span class="kw1">echo</span> <span class="re0">$sf_data</span><span class="sy0">-&gt;</span><span class="me1">getRaw</span><span class="br0">&#40;</span><span class="st_h">'test'</span><span class="br0">&#41;</span><span class="sy0">;</span>
 <span class="sy0">=&gt;</span> <span class="sy0">&lt;</span>script<span class="sy0">&gt;</span>alert<span class="br0">&#40;</span>document<span class="sy0">.</span>cookie<span class="br0">&#41;</span><span class="kw2">&lt;/script&gt;</span></pre>

<p>実際にHTMLとして解釈されるHTMLを含む変数を必要とするたびに生データにアクセスしなければなりません。テンプレートをインクルードするためにデフォルトのレイアウトが<code>$sf_content</code>の代わりに<code>$sf_data-&gt;getRaw('sf_content')</code>を使う理由がこれで理解できたでしょう。出力エスケーピングが有効になったときに<code>$sf_content</code>が壊れるからです。</p>

<p><code>escaping_strategy</code>が<code>off</code>のとき、<code>$sf_data</code>はまだ使えますが、つねに名前のデータを返します。</p>

<blockquote class="tip"><p>
  symfony 1.0では<code>escaping_strategy</code>に対して2つの異なる値がありました。<code>bc</code>は現在<code>off</code>に、<code>both</code>は<code>on</code>に置き換えられました。これらの値を使ってもまだ機能しますが、エラーをロギングすることになります。</p>
</blockquote>

<a name="escaping.helpers" id="escaping.helpers"></a><h3>エスケーピングヘルパー</h3>

<p>エスケーピングヘルパー(escaping helper)は入力のエスケープバージョンを返す機能です。これらは<code>settings.yml</code>ファイルのなかでデフォルトの<code>escaping_method</code>として、もしくはビューのなかで特定の値のためのエスケーピングメソッドを指定するために提供されます。つぎのエスケーピングヘルパーが利用できます:</p>

<ul>
<li><code>ESC_RAW</code>: 値をエスケープしません。</li>
<li><code>ESC_SPECIALCHARS</code>: PHP関数の<code>htmlspecialchars()</code>を入力に適用する。</li>
<li><code>ESC_ENTITIES</code>: 引用形式として<code>ENT_QUOTES</code>でPHP関数の<code>htmlentities()</code>を入力に適用します。</li>
<li><code>ESC_JS</code>: HTMLとして使われる予定のJavaScriptの文字列のなかに入る値をエスケープする。これはJavaScriptの利用によってHTMLが動的に変更されるものをエスケープするために便利です。</li>
<li><code>ESC_JS_NO_ENTITIES</code>: エンティティを追加しないがJavaScriptの文字列のなかに入る値をエスケープする。これはダイアログボックスを利用して値を表示する場合に便利です(たとえば、<code>javascript:alert(myString);</code>のなかで使われる<code>myString</code>変数)。</li>
</ul>

<a name="escaping.arrays.and.objects" id="escaping.arrays.and.objects"></a><h3>配列とオブジェクトをエスケープする</h3>

<p>出力エスケーピングは文字列だけでなく、配列とオブジェクトに対しても機能します。オブジェクトもしくは配列である値はそれらのエスケープされた状態をそれらの子供に渡します。<code>escaping_strategy</code>を<code>on</code>にセットしたと仮定すると、リスト7-43はエスケーピングカスケードのお手本を示しています。</p>

<p>リスト7-45 - エスケーピング機能は配列とオブジェクトに対しても作用する</p>

<pre class="php">// クラスの定義
class myClass
{
  public function testSpecialChars($value = '')
  {
    return '&lt;'.$value.'&gt;';
  }
}
&nbsp;
// アクションのなか
$this-&gt;test_array = array('&amp;', '&lt;', '&gt;');
$this-&gt;test_array_of_arrays = array(array('&amp;'));
$this-&gt;test_object = new myClass();
&nbsp;
// テンプレートのなか
<span class="kw2">&lt;?php</span> <span class="kw1">foreach</span><span class="br0">&#40;</span><span class="re0">$test_array</span> <span class="kw1">as</span> <span class="re0">$value</span><span class="br0">&#41;</span><span class="sy0">:</span> <span class="sy1">?&gt;</span>
  <span class="kw2">&lt;?php</span> <span class="kw1">echo</span> <span class="re0">$value</span> <span class="sy1">?&gt;</span>
<span class="kw2">&lt;?php</span> <span class="kw1">endforeach</span><span class="sy0">;</span> <span class="sy1">?&gt;</span>
 =&gt; &amp;amp; &amp;lt; &amp;gt;
<span class="kw2">&lt;?php</span> <span class="kw1">echo</span> <span class="re0">$test_array_of_arrays</span><span class="br0">&#91;</span><span class="nu0">0</span><span class="br0">&#93;</span><span class="br0">&#91;</span><span class="nu0">0</span><span class="br0">&#93;</span> <span class="sy1">?&gt;</span>
 =&gt; &amp;amp;
<span class="kw2">&lt;?php</span> <span class="kw1">echo</span> <span class="re0">$test_object</span><span class="sy0">-&gt;</span><span class="me1">testSpecialChars</span><span class="br0">&#40;</span><span class="st_h">'&amp;'</span><span class="br0">&#41;</span> <span class="sy1">?&gt;</span>
 =&gt; &amp;lt;&amp;amp;&amp;gt;</pre>

<p>実際のところ、テンプレート内部の変数はあなたが期待した型ではありません。出力エスケーピングシステムはこれらを"デコレート"して、特別なオブジェクトに変換します:</p>

<pre class="php"><span class="kw2">&lt;?php</span> <span class="kw1">echo</span> <span class="kw3">get_class</span><span class="br0">&#40;</span><span class="re0">$test_array</span><span class="br0">&#41;</span> <span class="sy1">?&gt;</span>
 =&gt; sfOutputEscaperArrayDecorator
<span class="kw2">&lt;?php</span> <span class="kw1">echo</span> <span class="kw3">get_class</span><span class="br0">&#40;</span><span class="re0">$test_object</span><span class="br0">&#41;</span> <span class="sy1">?&gt;</span>
 =&gt; sfOutputEscaperObjectDecorator</pre>

<p>これはエスケープされた配列では通常のPHP関数(<code>array_shift()</code>、<code>print_r()</code>などの)がもはや機能しない理由を説明しています。しかし、まだこれらは<code>[]</code>を使うことでアクセスすることが可能で、<code>foreach</code>を使うことで展開され、これらは<code>count()</code>で正しい結果を返します(<code>count()</code>はPHP 5.2かそれ以降で動作します)。そしてテンプレートにおいて、ともかくデータはリードオンリーなので、たいていのアクセスは実際に動作するメソッドを通したものになります。</p>

<p><code>$sf_data</code>オブジェクトを通して生データをとり出す方法がまだあります。加えて、エスケープされたオブジェクトのメソッドは追加パラメーター: エスケーピングメソッドを受けとるために変更されます。テンプレート変数を表示するたびに代わりのエスケーピングメソッド、もしくはエスケーピングを無効にする<code>ESC_RAW</code>ヘルパーを選ぶことができます。リスト7-46の例をご覧ください。</p>

<p>リスト7-46 - エスケープされたオブジェクトのメソッドは追加パラメーターを受けとる</p>

<pre class="php"><span class="kw2">&lt;?php</span> <span class="kw1">echo</span> <span class="re0">$test_object</span><span class="sy0">-&gt;</span><span class="me1">testSpecialChars</span><span class="br0">&#40;</span><span class="st_h">'&amp;'</span><span class="br0">&#41;</span> <span class="sy1">?&gt;</span>
=&gt; &amp;lt;&amp;amp;&amp;gt;
// つぎの3行は同じ値を返す
<span class="kw2">&lt;?php</span> <span class="kw1">echo</span> <span class="re0">$test_object</span><span class="sy0">-&gt;</span><span class="me1">testSpecialChars</span><span class="br0">&#40;</span><span class="st_h">'&amp;'</span><span class="sy0">,</span> ESC_RAW<span class="br0">&#41;</span> <span class="sy1">?&gt;</span>
<span class="kw2">&lt;?php</span> <span class="kw1">echo</span> <span class="re0">$sf_data</span><span class="sy0">-&gt;</span><span class="me1">getRaw</span><span class="br0">&#40;</span><span class="st_h">'test_object'</span><span class="br0">&#41;</span><span class="sy0">-&gt;</span><span class="me1">testSpecialChars</span><span class="br0">&#40;</span><span class="st_h">'&amp;'</span><span class="br0">&#41;</span> <span class="sy1">?&gt;</span>
<span class="kw2">&lt;?php</span> <span class="kw1">echo</span> <span class="re0">$sf_data</span><span class="sy0">-&gt;</span><span class="me1">get</span><span class="br0">&#40;</span><span class="st_h">'test_object'</span><span class="sy0">,</span> ESC_RAW<span class="br0">&#41;</span><span class="sy0">-&gt;</span><span class="me1">testSpecialChars</span><span class="br0">&#40;</span><span class="st_h">'&amp;'</span><span class="br0">&#41;</span> <span class="sy1">?&gt;</span>
 =&gt; &lt;&amp;&gt;</pre>

<p>テンプレートのなかでオブジェクトを処理する場合、追加パラメーターのトリックを多く利用することになります。これがメソッド呼び出しで生データを得るための最速の方法だからです。</p>

<blockquote class="caution"><p>
  出力エスケーピングを有効にした場合、symfonyの通常の変数もエスケープされます。<code>$sf_user</code>、<code>$sf_request</code>、<code>$sf_param</code>と<code>$sf_context</code>はそのまま機能しますが、これらが持つメソッド呼び出しに<code>ESC_RAW</code>を最後の引数として追加しないかぎり、メソッドはエスケープされたデータを返すことを覚えておいてください。</p>
</blockquote>

<p>-</p>

<blockquote class="tip"><p>
  <strong>symfony 1.1の新しい機能</strong>: たとえXSSがセキュリティ上のもっとも共通する弱点の1つであったとしても、これは唯一の弱点ではありません。CSRFはとても有名なのでsyfmonyはフォームの保護機能を自動的に提供します。</p>
</blockquote>

<a name="summary" id="summary"></a><h2>まとめ</h2>

<p>プレゼンテーションレイヤー(presentation layer)を操作するためにあらゆる種類のツールを利用できます。ヘルパー(helper)のおかげで、テンプレート(template)を秒単位で作れます。レイアウト(layout)、部分テンプレート(partial - もしくはパーシャル)、コンポーネント(component)とコンポーネントスロット(component slot)によってモジュール性と再利用性の両ほうがもたらされます。ビュー(view)の設定においてたいていのページヘッダーを処理するために速く書けるYAMLを利用します。設定カスケード(configuration cascade)によってビューごとにすべての設定を定義しないですみます。動的なデータに依存するプレゼンテーションをすべて修正するために、アクションは<code>sfResponse</code>オブジェクトにアクセスできます。そして出力エスケーピングシステム(output escaping system)のおかげで、ビューはクロスサイトスクリプティング(XSS - Cross-Site Scripting)攻撃から安全です。</p>
</div>
<div class="navigation">
<hr/>
<table width="100%">
<tr>
<td width="40%" align="left"><a href="06-Inside-the-Controller-Layer.html">前の章</a></td>
<td width="20%" align="center"><a href="index.html">ホーム</a></td>
<td width="40%" align="right"><a href="08-Inside-the-Model-Layer.html">次の章</a></td>
</tr>
</table>

</div>
</body>

</html>
